Friday, February 6, 2009

C++ bitwise operators

Bit operations are efficient and most programmers know them well. Still, using them effectively can be tricky. I'll make a cursory overview explaining in depth what bit operations are all about.

Bits
In standard computer jargon, all data is ultimately stored in bits which are grouped into different group sizes called bytes, words, double words, and quads. Modern CPUs now even allow for groups of octets or more. A byte holds 8 bits and for the rest of this discussion, I will be working on 8 bits at a time for simplicity's sake. All of the rules will still apply to higher order groupings. For the sake of this discussion, we won't discuss integer values. We will only be discussing unsigned integers.

The binary numbering system was invented by Leibnitz in 1679 a long time ago and in many ways it works like decimal. In decimal, we can count numbers 0-9 and once we pass 9, we add another digit to the front (left), and we roll over the previous digits to 0 making it complete number 10 (or 100 or 1000). Binary works he same but with only two digits, and so the roll over happens more often.

I'd like you to think of the 1's and 0's in two different ways. First, they are like light switches in a very real sense. A 1means 'on' and a 0 means 'off'. We often talk of bits being on or off. Secondly, I'd like you to think of true and false. Bits on (1's) are true and bits off (0's) are false. This way of thinking is where binary was formalized: from a man named George Boole c.1850. Anyway, these three ways of viewing binary are largely interchangeable and a matter of preference or notational ease.

If you think of powers of two, e.g. 1, 2, 4, 8, 16, then you begin to see the nature of bits and how they work in bytes. Each column of numbers, starting from the right, represents a higher power of two. The left most bit has a value of 1, the second most has a value of 2, and so on. The 8th column in a byte holds a value of 128. Here is an equivalence chart. I put 0's at the front to align the columns.

001 = 00000001
002 = 00000010
004 = 00000100
008 = 00001000
016 = 00010000
032 = 00100000
064 = 01000000
128 = 10000000

Other numbers use multiple bits. For example:

03 = 00000011
24 = 00011000

A byte can hold values between 0 and 255. The number 0 is represented by turning off all bits and 255 is represented by turning on all bits.

And
This is one of the two most common programmer bitwise operators. And may not be, however, what you think. The And operator is exactly defined the same way as in the field of mathematics called set theory. An And operation takes two parameters and 'ands' them. The result is only true (on) if two parameters hold the same value. The ampersand is the bitwise and operator. And is often used to remove any bits that two values don't share which nearly always reduces the number of bits set (unless both original values are the same).

U8 x = 1;
U8 y = 1;
U8 z = x & y; // z is now set to 1

x = 01
&
y = 01
----------
z = 01

but if you have different values, then z may be false.
x = 2;
y = 1;
z = x & y; // x sets the second bit, y sets the first bit and since they are different bits, z = 0

x = 10
&
y = 01
----------
z = 00

This obviously becomes much more complex for a full byte.

x = 126;
y = 17;
z = x & y;

x = 0111 1110
&
y = 0001 0001
----------
z = 0001 0000

At it's simplest, if a bit is on in one variable and it is on in a second variable then when you use the bitwise and operator, that bit will be on (or set) in the result. The bit table looks like this.
0 = 0 0
0 = 0 1
0 = 1 0
1 = 1 1

Or
This is another common bitwise operator. The Or operator also takes two parameters and if either parameter has a bit set on, then the result will have the bit on. This also applies if both of the parameters have the same bit set. Or is often used to "slam" two values together creating an aggregate containing all bits. The character on your keyboard used for this operation is the 'pipe' which looks like this | . On most keyboards, it simply looks like a vertical line, or a vertical line split in the middle.

U8 x = 1;
U8 y = 1;
U8 z = x | y; // z is now set to 1, just like for x and y

x = 1;
y = 2;
z = x | y; // z now equals 3, essentially the columns of the binary become on in the result

x = 01
&
y = 10
----------
z = 11

Here is that bitwise table (logic table)

0 = 0 0
1 = 0 1
1 = 1 0
1 = 1 1

Xor
Possibly the most complex concept of all of the bitwise operators, xor takes two parameters for input and if a single bit between them is on, the result is on. But if both are off or both are on, then the result is off. On your keyboard, often above the 6, is the ^ key which is called the caret (or up caret). This operator works like this.

int x = 3;
int y = 6;
int z = x ^ y;

x = 00000011
x = 00000110
z = 00000101

Here is that bitwise table (logic table)
0 = 0 0
1 = 0 1
1 = 1 0
0 = 1 1

Clarifying further, if a bit is set in either parameter, but not both, then the resultant is set to on. But if neither bit is set in either parameter, or both are set, then the resultant bit is set to 0.

Not
This operator is fairly rare among all of our bit operators. Not flips all bits that are currently on to off and all bits that are off to on. It's pretty basic and simply flips the state of each bit. If the bit is on, it is flipped to off and if it is off, it is flipped on.

The character on your keyboard for this operator is the tilde which is probably in the upper left of your keyboard and looks like this ~ . Ths is a unary operator meaning that it only needs a single input.

int x = 3;
int z = ~x; // this is now 255-3 (255 minus 3) = 252

x = 0000001
1
z = 11111100

No table is needed.

Bit Shift Left
This one is vary basic. Simply take all of the bits and move them to the left. YOu are able to specify how many places you wish to shift. This also has the effect of multiplying by two, since you are moving places kind of like shifting a 1 over to the left multiplies it by ten (10 <- 1). The operator uses the less than character twice (left caret) and looks like this <<. Any bits on the top are shifted off into nothingness.

int x = 3;
int y = x << 1;
int z = x << 1;
int q = x << 7; // we lost a bit

x = 00000011
y = 00000110
z = 00001100
q = 10000000

Bit Shift Right
Nearly identical in concept to bit shift left, this operator rotates the bits to the right. This is the less than symbol (right caret) doubled and looks like this >> . Bits too low are shifted into nothingness.

int x = 6;
int y = x >> 1;
int z = x >> 2;
int q = x >> 3;

x = 00000110
y = 00000011
z = 00000001
q = 00000000

Supplementary
Some other things to consider are the assignment operators. These include the following:
&=
|=
^=
>>=
<<= There is no ~= operator but it only works on a single value (unary) and thus doen't need one. All of the assignment operators only need one value on the right side of the expression.
x &= 3; // bitwise and x with 3 and store the result in x
x |= 3; // bitwise or x with 3 and store the result in x
x ^= 3; // bitwise xor x with 3 and store the result in x
x >>= 3; // bitshift x right three places and store the result in x
x <<= 3; // bitshift x left three places and store the result in x

Examples:

convert to upper case:
char lower_case_x = 'a'; // 97
char upper_case_x = x & 223;

lower_case_x = 01100001
223 = 01011111
upper_case_x = 01000001

convert to lower case:
char upper_case_x = 'A'; // 65
char lower_case_x = x | 32;

upper_case_x = 01000001
32 = 00100000
lower_case_x = 01100001

fast divide by two:
BYTE x = 15;
BYTE half_x = x >> 1; // half_x = 7

x = 00001111
half_x = 00000111

There are many other cool bit operations, but these ones are common.

This is the text from the HP support site on bitwise operators put into a terse form:

exp1 << exp2

Left shifts (logical shift) the bits in exp1 by exp2 positions.

exp1 >> exp2

Right shifts (logical or arithmetic shift) the bits in exp1 by exp2 positions.

exp1 & exp2

Performs a bitwise AND operation.

exp1 ^ exp2

Performs a bitwise OR operation.

exp1 | exp2

Performs a bitwise inclusive OR operation.

~exp1

Performs a bitwise negation (one's complement) operation.

1 comment:

subha said...

Great work! Thanks to Admin for Sharing the list of High DA link building Sites. This list will Surely help many of us. I Bookmarked and Shared your Link in Facebook. Really backlinks from High DA Sites helps for better Ranking. Keep sharing such good articles.
C and C++ Training Institute in chennai | C and C++ Training Institute in anna nagar | C and C++ Training Institute in omr | C and C++ Training Institute in porur | C and C++ Training Institute in tambaram | C and C++ Training Institute in velachery