Bitwise Operators

From Rosetta Code

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

Bitwise 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.

For example, 0x37 & 0x49 = ((0x30 & 0x40) | (0x07 & 0x09))

Filtering

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. <lang C>if ((foo & 1) == 0) {

  // your code for what happens when foo is even goes here

} else {

  // your code for what happens when foo is odd goes here

}</lang>

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. <lang 6502asm>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.</lang>

Random Chance

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.

<lang C> if ((rand & 3) == 0) {

  //1 in 4 chance of occurring

} else {

  //3 in 4 chance of occurring

}

if ((rand & 15) == 0) {

  //1 in 16 chance of occurring

} else {

  //15 in 16 chance of occurring

}</lang>

OR

Bitwise 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

etc.

Failsafes

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. 0xFF00 and 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.

XOR

eXclusive OR, often abbreviated to XOR, ^ 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:

  • If A XOR B = C, then A XOR C = B and B XOR C = A.
  • A bit XOR'd with 1 will flip. A bit XOR'd with zero won't change.
  • A bitwise NOT is the same as XOR -1.
  • A ^ A = 0. Furthermore, if A ^ B = 0, then A = B.
  • If ((A ^ B) & C) = 0, then A and B both share the bits of C in common.


Toggling

A flag register XOR'd with a given value will flip those particular bits, and leave the rest alone.

NOT

A bitwise NOT, or ~ 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.

Among AND, OR, XOR, and NOT, only XOR and NOT are reversible.


Citations

  1. [Beyond 8-Bit Unsigned Comparisons by Bruce Clark]