As the name implies, bitwise operators look at the individual bits of a number. Computers store everything in binary, therefore bitwise operations can be used on all types of data, whether the source code displays the data in binary or not. The computer will look at those numbers' binary representations to calculate the result.
AND, often abbreviated to
&, compares each individual bit of two different numbers, and outputs a 1 if they are both 1, and 0 otherwise.
10101101 AND 00110010 ------------ 00100000
A few properties of
AND that aren't readily apparent.
For all numbers A:
A & 0 = 0
A & A = A
A & -1 = A (remember that -1 = FF)
- Every 4 binary digits of A and B can be
ANDed separately and concatenated, and the result is the same.
0x37 & 0x49 = ((0x30 & 0x40) | (0x07 & 0x09))
AND is useful for filtering out unwanted bits for a comparison. A practical example is checking whether a number is odd or even. This uses the property that the least significant bit of all even numbers is 0, and all odd numbers is 1.
if ((foo & 1) == 0)
// your code for what happens when foo is even goes here
// your code for what happens when foo is odd goes here
Filtering is also useful for checking the status of a flag variable, where each bit represents a different options setting. This example is for 6502 Assembly.
FLAG_SCROLL equ %10000000 ;0 = no scrolling, 1 = scrolling enabled.
; This label represents a constant so that we don't have to remember what the flags mean.
LDA statusFlags ;get the variable statusFlags, an 8 bit value where each bit controls a different aspect of our program.
AND #FLAG_SCROLL ;AND statusFlags with the binary value 0b10000000 (decimal 128)
BNE ScrollScreen ;the corresponding bit of statusFlags was set, so allow the screen to scroll.
Given the output of a random number generator with all equally likely outcomes, you can use
AND with that output to create random occurrences. If is a power of 2, then to create a random event with probability , you just need to
AND the RNG output with . In the example below,
rand is a randomly generated number. Its size doesn't change the probabilities listed below.
if ((rand & 3) == 0)
//1 in 4 chance of occurring
//3 in 4 chance of occurring
if ((rand & 15) == 0)
//1 in 16 chance of occurring
//15 in 16 chance of occurring
OR, often abbreviated to
| (SHIFT+\), compares each individual bit of two different numbers, and outputs a 0 if both are 0, and a 1 otherwise.
10101101 OR 00110010 ------------ 10111111
When we say "or" in the English language, we usually mean "one or the other, but not both." This isn't the case in programming. That's actually a different operator which will be covered later.
A few properties of OR that aren't readily apparent. For all numbers A:
A | 0 = A
A | A = A
A | -1 = -1
The first property implies that if a subset of a byte is a sequence of zeroes, then
ORing that sequence of zeroes with any bit combination will result in the same bit combination. For example:
%11 000 111 | %00 101 000 = %11 101 111 %11 000 111 | %00 111 000 = %11 111 111 %11 000 111 | %00 001 000 = %11 001 111
Bits that get
ORed with 1 always equal 1, regardless of their original value. If you have a variable that you want to guarantee at least certain bits are set, you can OR them with those bits. The nice thing about this method is that the actual value of that variable need not be compared to anything. Those bits will get set either way.
Combining two values without addition
If you have two values in separate "nibbles", e.g.
0x00DD, then an
OR of these two will combine them, e.g.
0xFFDD. This is just an extension of the property that
A | 0 = A.
eXclusive OR, often abbreviated to
^ or called
EOR in some languages, compares each individual bit of two different numbers, and outputs a 1 if they are different and 0 if they are the same.
10101101 XOR 00110010 ------------ 10011111
A few properties about
XOR that aren't readily apparent:
A XOR B = C, then
A XOR C = Band
B XOR C = A.
- A bit
XOR'd with 1 will flip. A bit
XOR'd with zero won't change.
- A bitwise
NOTis the same as
A ^ A = 0. Furthermore, if
A ^ B = 0, then
A = B.
((A ^ B) & C) = 0, then A and B both share the bits of C in common.
A flag register
XOR'd with a given value will flip those particular bits, and leave the rest alone.
~ takes one number as an argument and flips all its bits. This has its uses, especially when reading video game controllers, but is a little more limited than the others.
NOT are reversible.