%% Bit-Wise Operations
% This topic shows how to use bit-wise operations in MATLAB® to manipulate the bits of numbers. Operating on bits is directly supported by most modern CPUs. In many cases, manipulating the bits of a number in this way is quicker than performing arithmetic operations like division or multiplication.
%
%% Number Representations
% Any number can be represented with bits (also known as binary digits). The binary, or base 2, form of a number contains 1s and 0s to indicate which powers of 2 are present in the number. For example, the 8-bit binary form of 7 is
% 00000111
% A collection of 8 bits is also called 1 byte. In binary representations, the bits are counted from the right to the left, so the first bit in this representation is a 1. This number represents 7 because
% 2^2 +2^1 +2^0 =7\ldotp
% When you type numbers into MATLAB, it assumes the numbers are double precision (a 64-bit binary representation). However, you can also specify single-precision numbers (32-bit binary representation) and integers (signed or unsigned, from 8 to 64 bits). For example, the most memory efficient way to store the number 7 is with an 8-bit unsigned integer:

a = uint8(7)

% You can even specify the binary form directly using the prefix 0b followed by the binary digits (for more information, see Specify Hexadecimal and Binary Numbers). MATLAB stores the number in an integer format with the fewest number of bits. Instead of specifying all the bits, you need to specify only the left-most 1 and all the digits to the right of it. The bits to the left of that bit are trivially zero. So the number 7 is:

b = 0b111

% MATLAB stores negative integers using two's complement. For example, consider the 8-bit signed integer -8. To find the two's complement bit pattern for this number:
% Start with the bit pattern of the positive version of the number, 8:  00001000.
% Next, flip all of the bits:  11110111.
% Finally, add 1 to the result:  11111000.
% The result, 11111000, is the bit pattern for -8:

n = 0b11111000s8

% MATLAB does not natively display the binary format of numbers. For that, you can use the dec2bin function, which returns a character vector of binary digits for positive integers. Again, this function returns only the digits that are not trivially zero.

dec2bin(b)

% You can use bin2dec to switch between the two formats. For example, you can convert the binary digits 10110101 to decimal format with the commands

data = [1 0 1 1 0 1 0 1];
dec = bin2dec(num2str(data))

% The cast and typecast functions are also useful to switch among different data types. These functions are similar, but they differ in how they treat the underlying storage of the number:
% cast — Changes the underlying data type of a variable.
% typecast — Converts data types without changing the underlying bits.
% Because MATLAB does not display the digits of a binary number directly, you must pay attention to data types when you work with bit-wise operations. Some functions return binary digits as a character vector (dec2bin), some return the decimal number (bitand), and others return a vector of the bits themselves (bitget).
%
%% Bit Masking with Logical Operators
% MATLAB has several functions that enable you to perform logical operations on the bits of two equal-length binary representations of numbers, known as bit masking:
% bitand — If both digits are 1, then the resulting digit is also a 1. Otherwise, the resulting digit is 0.
% bitor — If either digit is 1, then the resulting digit is also a 1. Otherwise, the resulting digit is 0.
% bitxor — If the digits are different, then the resulting digit is a 1. Otherwise, the resulting digit is 0.
% In addition to these functions, the bit-wise complement is available with bitcmp, but this is a unary operation that flips the bits in only one number at a time.
% One use of bit masking is to query the status of a particular bit. For example, if you use a bit-wise AND operation with the binary number 00001000, you can query the status of the fourth bit. You can then shift that bit to the first position so that MATLAB returns a 0 or 1 (the next section describes bit shifting in more detail).

n = 0b10111001;
n4 = bitand(n,0b1000);
n4 = bitshift(n4,-3)

% Bit-wise operations can have surprising applications. For example, consider the 8-bit binary representation of the number n=8:
% 00001000
% 8 is a power of 2, so its binary representation contains a single 1. Now consider the number \left(n-1\right)=7:
% 00000111
% By subtracting 1, all of the bits starting at the right-most 1 are flipped. As a result, when n is a power of 2, corresponding digits of n and \left(n-1\right) are always different, and the bit-wise AND returns zero.

n = 0b1000;
bitand(n,n-1)

% However, when n is not a power of 2, then the right-most 1 is for the 2^0 bit, so n and \left(n-1\right) have all the same bits except for the 2^0 bit. For this case, the bit-wise AND returns a nonzero number.

n = 0b101;
bitand(n,n-1)

% This operation suggests a simple function that operates on the bits of a given input number to check whether the number is a power of 2:
% function tf = isPowerOfTwo(n)
%   tf = n && ~bitand(n,n-1);
% end
% The use of the short-circuit AND operator && checks to make sure that n is not zero. If it is, then the function does not need to calculate bitand(n,n-1) to know that the correct answer is false.
%
%% Shifting Bits
% Because bit-wise logical operations compare corresponding bits in two numbers, it is useful to be able to move the bits around to change which bits are compared. You can use bitshift to perform this operation:
% bitshift(A,N) shifts the bits of A to the left by N digits. This is equivalent to multiplying A by 2^N.
% bitshift(A,-N) shifts the bits of A to the right by N digits. This is equivalent to dividing A by 2^N.
% These operations are sometimes written A<<N (left shift) and A>>N (right shift), but MATLAB does not use << and >> operators for this purpose.
% When the bits of a number are shifted, some bits fall off the end of the number, and 0s or 1s are introduced to fill in the newly created space. When you shift bits to the left, the bits are filled in on the right; when you shift bits to the right, the bits are filled in on the left.
% For example, if you shift the bits of the number 8 (binary: 1000) to the right by one digit, you get 4 (binary: 100).

n = 0b1000;
bitshift(n,-1)

% Similarly, if you shift the number 15 (binary: 1111) to the left by two digits, you get 60 (binary: 111100).

n = 0b1111;
bitshift(15,2)

% When you shift the bits of a negative number, bitshift preserves the signed bit. For example, if you shift the signed integer -3 (binary: 11111101) to the right by 2 digits, you get -1 (binary: 11111111). In these cases, bitshift fills in on the left with 1s rather than 0s.

n = 0b11111101s8;
bitshift(n,-2)

%
%% Writing Bits
% You can use the bitset function to change the bits in a number. For example, change the first bit of the number 8 to a 1 (which adds 1 to the number):

bitset(8,1)

% By default, bitset flips bits to on or 1. You can optionally use the third input argument to specify the bit value.
% bitset does not change multiple bits at once, so you need to use a for loop to change multiple bits. Therefore, the bits you change can be either consecutive or nonconsecutive. For example, change the first two bits of the binary number 1000:

bits = [1 2];
c = 0b1000;
for k = 1:numel(bits)
    c = bitset(c,bits(k));
end
dec2bin(c)

% Another common use of bitset is to convert a vector of binary digits into decimal format. For example, use a loop to set the individual bits of the integer 11001101.

data = [1 1 0 0 1 1 0 1];
n = length(data);
dec = 0b0u8;
for k = 1:n
    dec = bitset(dec,n+1-k,data(k));
end
dec
dec2bin(dec)

%
%% Reading Consecutive Bits
% Another use of bit shifting is to isolate consecutive sections of bits. For example, read the last four bits in the 16-bit number 0110000010100000. Recall that the last four bits are on the left of the binary representation.

n = 0b0110000010100000;
dec2bin(bitshift(n,-12))

% To isolate consecutive bits in the middle of the number, you can combine the use of bit shifting with logical masking. For example, to extract the 13th and 14th bits, you can shift the bits to the right by 12 and then mask the resulting four bits with 0011. Because the inputs to bitand must be the same integer data type, you can specify 0011 as an unsigned 16-bit integer with 0b11u16. Without the -u16 suffix, MATLAB stores the number as an unsigned 8-bit integer.

m = 0b11u16;
dec2bin(bitand(bitshift(n,-12),m))

% Another way to read consecutive bits is with bitget, which reads specified bits from a number. You can use colon notation to specify several consecutive bits to read. For example, read the last 8 bits of n.

bitget(n,16:-1:8)

%
%% Reading Nonconsecutive Bits
% You can also use bitget to read bits from a number when the bits are not next to each other. For example, read the 5th, 8th, and 14th bits from n.

bits = [14 8 5];
bitget(n,bits)

%
% Copyright 2019 The MathWorks, Inc.
%