[OT] help w/ bitwise comparison operators
Erik Price
eprice at ptc.com
Fri Mar 21 13:30:10 EST 2003
pll at lanminds.com wrote:
> Would you mind posting a summary of the helpful tips, tricks, and
> shortcuts sent your way? I'm rather interested in understanding this
> stuff a little better myself.
Sure. In fact, they say you really know something well when you can
explain it to someone else, and this gives anyone a chance to correct me
if I'm wrong in what I think I know. Here's some of the things I
learned, combined with what I had already learned from my book (please
*do* correct me if I'm wrong):
1. The unary bitwise NOT operator (~) has a shortcut, but one which
only works when two's complement is in effect. On systems in which
one's complement is in effect, it doesn't work. The shortcut is that
any number n has a bitwise NOT of -n - 1. So
~5 == -6
~-12 == 11
Because I'm fortunate enough to be working in Java where you're writing
for only one platform (the JVM, which has a spec), I don't have to worry
about exceptions to this for the test.
2. Other than the NOT operator, the bitwise operators are binary
operators, working on pairs of numbers. The bitwise AND operator
returns a 1 for each pair of bits that are both 1.
So in the case of
11001 & 10011
the result is 10001 (because only the first and last digits are *both* 1).
The bitwise OR (|) operator returns a 1 for situations in which either
pair of bits has a 1.
So in the case of
11001 | 10011
the result is 11011 (because the only place in both numbers where there
is no 1 is the third digit).
The bitwise XOR (^) operator returns a 1 for situations in which either
pair of bits, but not both, has a 1 (hence the name "exclusive OR", or XOR).
So in the case of
11001 ^ 10011
the result is 01010 (because in the first, third, and fifth digits,
either both numbers are 0 or 1).
The short circuit operators AND (&&) and OR (||) work just like their
regular counterparts except they stop evaluating once they "know" the
result (AND stops evaluating if the first operand is false, and OR stops
evaluating if the first operand is true).
3. So my original question, "does anyone know any mental shortcuts for
working with bitwise operators", should have been phrased as "does
anyone know any mental shortcuts for converting decimal numbers to
binary". The answer, which a couple of people provided, was that it's
much easier to convert to binary (even if only in your head) when you
are working from octal or hexadecimal, and that it's not too difficult
to convert from decimal to octal or hexadecimal.
Several ways were suggested:
a) Convert the number to hex, then do the comparison a byte at a time in
your head using a table:
& 0x01 0x02 ... 0xff
0x01 0x01 0x00 0x01
0x02 0x00 0x02 0x02
....
0xff 0x01 0x02 0xff
b) Convert the number to octal using a simple recursive divide-by-eight
solution:
divide the number by eight, store the remainder as the low bit depth
(rightmost number), then repeat the process with the quotient.
123 / 8 = 15 remainder 3 -- 3 is rightmost digit (3)
15 / 8 = 1 remainder 7 -- 7 is next to 3 (73)
we don't divide 1 by 8 -- 1 is next to 7 (173)
so 123 in octal is 0173
From octal it's much easier to see the binary form of the number:
1 7 3
001 111 011
And from binary it's much easier to do a bitwise calculation.
c) Another way to convert to binary is to simply keep dividing by two
and assigning 1 if there's a remainder and 0 if there isn't, then read
in reverse to get the binary number:
<quote>
If a number is even, dividing it by 2 will have 0 remainder.
If it is odd, dividing it by 2 will have a 1 remainder. Dividing
by 2 is so easy that I, at least, can just write down a column of
successive halvings, along with 1s and 0s for their oddness.
459 1
229 1
114 0
57 1
28 0
14 0
7 1
3 1
1 1
Reading from bottom to top, we again get 111001011. In this
presentation you stop when the quotient is 1, since you've already
written down the remainder that you'd get by dividing 1 by 2 when
you write down the oddness. Remainder when dividing by 2 is easier
than quotient.
</quote>
d) A final useful tip mentioned: as long as x is not zero,
x & -x
will always evaluate to a power of two, which means only one bit is set
in the number (the least significant of the bits of x that were 1s).
4. And everyone agreed that it's foolish to do these kinds of
computations in your head when there's no good reason not to use a
computer to do it. My personal preference is to use Python since the
interactive interpreter works just like a calculator, though any
scripting language should probably be able to handle the calculations.
(Here's a quick sample:)
|$ python
|Python 2.2.2 (#1, Dec 31 2002, 12:24:34)
|[GCC 3.2 20020927 (prerelease)] on cygwin
|Type "help", "copyright", "credits" or "license" for more information.
|>>> 12 & 14
|12
|>>> 12 | 14
|14
|>>> 12 ^ 14
|2
|>>> ~12
|-13
|>>> myResult = 0x5422CA66 & 458
|>>> myResult
|66
|>>> hex(myResult)
|'0x42'
(hey, it wouldn't be a LUG without a little evangelism, would it? :)
Much thanks to Bill, Jason, Kevin, and YATArchivist.
Erik
More information about the gnhlug-discuss
mailing list