Emily Cain (@data_bae) γ»4 min read

I first came across bitwise operations as part of an Advent of Code challenge in 2017. I was thoroughly confused. "How can you do AND on two numbers? That doesn't make sense!" I dutifully used the AND operator in whatever language I was using for the challenge (probably Go) and just accepted not knowing what it meant.

My next encounter was in a workplace discussion group where we learned about using AND operators to filter packets, using tcpdump. I asked enough questions to actually understand what was going on with these bitwise operations, and I want to share one of the methods I came up with in this article. It involves counting on your fingers in binary and then using your hands to perform bitwise arithmetic -- no computer needed. I don't know if anyone else has done it quite like this, but I find it helpful.

# Background

Any computer system you use represents information as a series of 0s and 1s, using base 2 or binary to represent numbers. Bitwise operators perform a Boolean operation on each bit to reach the final result.

For example, let's say we want to find 6 AND 3.

0110 (6)
0011 (3)
----
0010 (2)


Breaking this down:

In the 2^0 (1's) place, the first value is 0 (false) and the second value is 1 (true). false AND true = false.

In the 2^1 (2's) place, the first value is 1 (true) and the second value is 1 (true). true AND true = true.

In the 2^2 (4's) place, the first value is 1 (true) and the second value is 0 (false). true AND false = false.

In the 2^3 (8's) place, the first value is 0 (false) and the second value is 0 (false). false AND false = false.

To summarize: for each place or column, do the Boolean logic operation on the input values in that column to get the output for that column.

You use the same process for doing other bitwise operations.

OR (true if either value is true):

0110 (6)
0011 (3)
----
0111 (7)


XOR (true if the two values are different):

0110 (6)
0011 (3)
----
0101 (5)


NOT is a unary operator, which is to say it takes only one input, and it reverses the value of each column (or bit).

0101 (5)
----
1010 (10)


You can play with bitwise arithmetic using this calculator.

# Finger Method

We'll start by learning to finger-count in binary.

Some finger counting systems start with the thumb, but I am going to use the index finger for 1 because then each hand represents a nibble, or half-byte, which can be represented by a single hexadecimal digit. (It also means I can use my thumb to hold down any unused fingers.) The middle finger is 2, the ring finger is 4, and the pinky is 8.

1, or 0001:

2, or 0010:

3, or 0011, or 2^1 + 2^0:

7, or 0111, or 2^2 + 2^1 + 2^0:

12, or 1100, or 2^3 + 2^2, or C in hexadecimal:

15, or 1111, or 2^3 + 2^2 + 2^1 + 2^0, or F in hexadecimal:

# AND

For the AND operation, use your left hand to make the first number and your right hand to make the second number. For each hand, the index finger should always represent 1, the pinky 8.

Here's 6 on the left hand and 3 on the right.

Now take the two hands and place them together, palms touching, fingers tented.

The fingers that are touching at the top represent the answer (2).

Some more examples:

12 AND 7 = 4

10 AND 5 = 0

# OR

Let's use the same inputs with the OR operator.

Here's 6 on the left hand and 3 on the right.

Now take the two hands and place them together, palms touching, fingers tented.

The places with at least 1 finger up represent the answer (7).

Some more examples:

12 OR 7 = 15

10 OR 5 = 15

8 OR 1 = 9

# XOR

Here's 6 on the left hand and 3 on the right.

Now take the two hands and place them together, palms touching, fingers tented.

The places that have exactly one finger up represent the answer (5).

Some more examples:

12 XOR 7 = 11

10 XOR 5 = 15

# NOT

Take all the fingers that are up and put them down; put all the fingers that are down and put them up.

NOT 5 = 10

# Conclusion

Now you know how to do the bitwise operators on your fingers! Hopefully this helps you understand these operations in a more intuitive way.

Posted on by:

### Emily Cain (@data_bae)

web developer + security engineer. Python, SQL, JavaScript, Go

### Discussion

Brilliant pictures! Fun fact - using four fingers (a 4 bit nibble) as you have gives you a representation of one hexadecimal digit on each hand, so you can easily translate between the commonly written form (hex) and hands. Wanna evaluate (0xff431023 XOR 0x6742a7b2)? Work through the hex nibbles one pair at a time!

it's nibbles all the way down.... ;)

It all make sense now

π€AND π€ = π€
1001 AND 1001 = 1001
9 AND 9 = 9

See it upside-down andyou will get: 666. It's a secret invocation πΉ

With great power comes great responsability. Use only when need fix bugs in production.

Thank you for writing and publishing this! This is super helpful

Next thing to do would be to learn how to shift to the right a twoβs complement using fingers.

Nice :) And this scales up to the total number of people around you. (Granted they still have all their fingers.)

It's so weird to hear this. Back in the day, working with bits and bitwise operators was absolutely essential, and one of the earliest things learnt as a programmer

I learned to code in 2016 in Python and JavaScript. I don't have a formal CS education. A lot of the people out there building whole software applications used by millions of people have never touched lower-level code.

Is it really that new? A lot of the PHP apps out there were started 15 or 20 years ago and you don't need a formal CS background to do that either...

A lot of us don't have CS degrees, and are building applications you use every day. I'm learning the "foundational" concepts I never got when I was just starting out on my own, and I have to say they make a lot more sense to me having created software for a living for the last couple of years, than they would have if I'd tried to learn them in a classroom.

I don't have a formal CS background either - completely self taught. Started in about 1984 on a ZX Spectrum, and later moved to a Commodore Amiga, then a DOS based PC, then to Windows, then finally to Web based stuff (primarily developing on Linux/Macs). Working with bits was very necessary for dealing with direct manipulation of memory (video memory or whatever), and was/is an extremely efficient way to implement 'flags' within variables. Admittedly programming has moved past a lot of low level stuff these days, probably to the overall detriment of code efficiency and actual understanding of what goes on underneath the high level stuff.

Binary is used at a low level for sure, but it's really just looking at numbers in another way - that can be exceptionally useful in many situations.

Maybe! I see what you mean about memory manipulation but there are whole realms of programming people can do without ever worrying about memory. It's kind of like how most people who can drive don't have to worry about how their car is built--which allows the car, or the higher-level languages and frameworks, to become more and more advanced, efficient, and accessible.

I'm trying to learn low-level concepts now, partly for fun and partly because I'm about to start working in Security and it becomes important in e.g. network packet analysis and stopping memory-related vulnerabilities. But I know plenty of people who make whole programming careers without handling memory directly, in large part because they become experts in some other concept that abstracting away memory allows them to focus on.