Binary, Hex, and C0 Operators
Consider the decimal integer 15122. What is its value in binary?
Using our algorithm from class, divide by 2 repeatedly, and record the
remainders:
15122 / 2 = 7561 R 0
7561 / 2 = 3780 R 1
3780 / 2 = 1890 R 0
1890 / 2 = 945 R 0
945 / 2 = 472 R 1
472 / 2 = 236 R 0
236 / 2 = 118 R 0
118 / 2 = 59 R 0
59 / 2 = 29 R 1
29 / 2 = 14 R 1
14 / 2 = 7 R 0
7 / 2 = 3 R 1
3 / 2 = 1 R 1
1 / 2 = 0 R 1
Reading up from the bottom, 15122 in decimal is 11101100010010 in binary.
If we stored this as a 32-bit siged integer, then it would be stored as:
00000000000000000011101100010010
(Note how the leftmost bit is 0, indicating a postive integer.)
What is this value expressed in hexadecimal? Break up the binary number into
groups of 4 bits and translate each to its equivalent hex digit:
0000 0000 0000 0000 0011 1011 0001 0010
0 0 0 0 3 B 1 2
Check this in coin by entering 0x00003B12; and you should
see 15122 (int) printed out.
What is the negation of 0x00003B12 (using 2's complement notation)?
To find this, flip all the bits
and then add 1:
0000 0000 0000 0000 0011 1011 0001 0010 (15122 in binary)
1111 1111 1111 1111 1100 0100 1110 1101 (flip all the bits)
1111 1111 1111 1111 1100 0100 1110 1110 (add 1)
F F F F C 4 E E (-15122 in hex)
Again, use coin to check this value. If you add 0x00003B12 and
0xFFFFC4EE in coin you should get 0. (Why?)
How do you compute the negation of integer i using C0 operators?
Obviously, you can just write -i. But using the logical and arithmetic operators,
you could use bitwise-exclusive-or (bitwise-xor):
(i ^ 0xFFFFFFFF) + 1
Think: Why does this work?
Now let's look at the shift operators. If we take the value 15122 and shift right
one bit in coin, we get the value 7561. It looks like a shift right
of one bit divides the value by 2. If we take 15122 and shift left by one bit,
we get 30244. So shifting left by 1 bit multiplies by 2.
What happens to the bit that gets shifted "off"? It is ignored.
What happens to the bit position that becomes "empty"? For a left shift, the
bit 0 is shifted in from the right into the rightmost bit. Note that a left
shift may change the sign of the integer. (Do you see why?)
For a right shift,
however, the sign bit is duplicated and shifted in from the left into the
leftmost bit, so the sign of the resulting value doesn't change in a right shift.
This is called arithmetic right shift. (There is also the notion of a
logical right shift where a 0 is always shifted in from the left into
the leftmost bit, but this could change the sign of the number.)
Suppose you want the rightmost 2 bits of an integer i?
One way to do this is
to use the bitwise-and operator like we did with the image example above:
i & 0x00000003
Another way you might think of doing this is using the modulo operator (%).
If we were to divide by 4, this is equivalent to shifting right two times.
The two bits that gets lost represent the bits we want. So if we use
modulo (%), this is a division operation but you get back the remainder
instead of the quotient, and the remainder is these two bits that we want.
So you might think about doing this:
i % 4
But this doesn't work if the integer is negative. If the integer is negative
and you want the rightmost two bits, you should use the bitwise-and operator,
not modulo. Experiment in coin and see why.
Exercise
Suppose you want the alpha channel of a pixel p.
Two solutions come to mind:
(p & 0xFF000000) >> 24
(p >> 24) & 0xFF
The first solution is incorrect, while the second solution is correct.
Why?
written by Tom Cortina, 1/19/11