2007-10-29

## Bit operations

Posted by scvalexIn this article I’ll begin by defining binary numbers and describe the basic operations. Afterwords, I’ll show you several of the most common uses of binary numbers.

Humans work with digits in base *10*, and we’re quite good at it. Computers, on the other hand, use base *2* and it shouldn’t come as a surprise that they’re **extremely** good at it. Today’s high level languages do a lot to hide this fact from us, but, still, a fairly good grasp of binary numbers is essential to working with computers, especially programming them.

#### Binary numbers

Mathworld defines binary as:

The base 2 method of counting in which only the digits 0 and 1 are used.

Basically, the binary representation of a number is the way of writing that number, uniquely, using only the digits *0* and *1*. These are the binary representations of the first *16* natural numbers:

`0 = 0000`

1 = 0001

2 = 0010

3 = 0011

4 = 0100

5 = 0101

6 = 0110

7 = 0111

8 = 1000

9 = 1001

10 = 1010

11 = 1011

12 = 1100

13 = 1101

14 = 1110

15 = 1111

Given a number in base *10*, how do you find the representation in base *2*? You take the number and divide it repeatedly by *2* taking note of the remainder. After you’ve reached *0*, write the remainders in **reverse** order. That’s the binary number! Here’s an example for *13*:

So,

Now, how do you get a decimal form a binary? This is even easier. Take the number in binary form and start from the right side. Multiply the first digit (from the right side) with *2 ^{0}*. Multiply the second digit with

*2*and add it to the result from the first multiplication. Multiply the third digit with

^{1}*2*and add it to what you have so far. … Do this for all the digits and you’ll get the decimal representation of the binary number.

^{2}#### Logical operations

All of the following operations work in the same way. Take every bit form the first number and the corresponding bit from the second number (if it exists) and compute the resulting bit using the operation’s truth table.

##### NOT

So, take each bit and reverse it.

`0000 becomes 1111`

0101 becomes 1010

1111 becomes 0000

It’s worthwhile to note that applying **NOT** twice, you get the original number unaltered.

##### AND

So, if both digits are *1* then the result is *1*, otherwise it is *0*.

##### OR

So, if either digit is *1*, then the result is *1*, otherwise it is *0*.

##### XOR (eXclusive OR)

So, if one of the digits it *1*, but not both, then the result is *1*, otherwise, the result is *0*.

##### SHL (SHift Left) and SHR (SHift Right)

These aren’t like the other operations in that they don’t rely on truth tables. To apply them, simply drop the left-most (right-most) digit and add a *0* digit to the right (left).

`After successive SHL operations,`

0011 becomes 0110,

0110 becomes 1100,

1100 becomes 1000,

1000 becomes 0000

`After successive SHR operations,`

1100 becomes 0110,

0110 becomes 0011,

0011 becomes 0001,

0001 becomes 0000

#### Common use: Fast multiplication/division by 2

To quickly multiply an integer by 2, simply shift left the number.

To quickly divide an integer by 2, simply shift right the number.

In C, this would be:

`a = a <> 1; /* Divide by 2 */`

a = a >> 1; /* Multiply by 2*/

#### Setting/Checking a certain bit

To check whether the *(n + 1) ^{th}* bit is set (1) or not (0), use this:

`a & 1<<n = 0 if the bit is NOT set`

a & 1< 0 if the bit is set

To set the *(n + 1) ^{th}* bit, use this:

`a = a | 1<<n;`

What am I doing here? In both cases I first compute *1<<n*. This is a binary number in which all digits are *0* but the *n ^{th}* digit is

*1*. Then, to check, I logically AND the two numbers. If the bit is set, then the result should be anything but

*0*. On the other hand, to set the bit, I logically OR the two numbers. If the bit was set, than this will have no effect. But if the bit was not set, it will be at the end.

#### Common use: bitsets

Chances are, at one time or another, you’ve had to use an array of boolean values. You’ve probably used something like this:

`char foo[100];`

foo[42] = 0; /* Equivalent of false */

foo[42] = 1; /* Equivalent of true*/

`OR`

`bool bar[100];`

bar[23] = false;

bar[23] = true;

This isn’t bad. Actually, in most cases it’s quite good. But if the number of elements is relatively small (less than *64*), there’s a better way, that is using **bitsets**.

Instead of an array use an int, then use the methods described above to set and check the bits.

`int a;`

a = 0; /* The entire “array” is set to false */

a |= 1<<3; /* The fourth bit is set */

if (a & 1<<3) /* Is the fourth bit set? */

a ^= 1<<3; /* If it is, flip it. */

#### Flipping bits

To flip a bit, XOR it by *1*.

`a ^= 1<<5; /* Flip the sixth bit */`

#### Putting it all together: Printing a binary number

This small C programme prints out the binary representation of *0, 1, …, 16*. (bitops.c)

#include <stdio.h> /* Print n as a binary number */ void printbitssimple(int n) { unsigned int i; i = 1<<(sizeof(n) * 8 - 1); while (i > 0) { if (n & i) printf("1"); else printf("0"); i >>= 1; } } /* Print n as a binary number */ void printbits(int n) { unsigned int i, step; if (0 == n) { /* For simplicity's sake, I treat 0 as a special case*/ printf("0000"); return; } i = 1<<(sizeof(n) * 8 - 1); step = -1; /* Only print the relevant digits */ step >>= 4; /* In groups of 4 */ while (step >= n) { i >>= 4; step >>= 4; } /* At this point, i is the smallest power of two larger or equal to n */ while (i > 0) { if (n & i) printf("1"); else printf("0"); i >>= 1; } } int main(int argc, char *argv[]) { int i; for (i = 0; i < 16; ++i) { printf("%d = ", i); printbits(i); printf("\n"); } return 0; }

Code should be fairly easy to understand. Good luck. Always open to comments.

Update: The next article in this series is Counting Bits.