This article is part of the sequence The Basics You Won’t Learn in the Basics aimed at eager people striving to gain a deeper understanding of programming and computer science.
Last time, we covered how does a processor work. We mentioned that he used instructions, which are encoded in numbers. But these numbers are stored in a computer in binary digits.
Today, I begin a series on posts on how binary numbers work.
Types of numeral systems
There are two kinds of numeral systems. Positional and non-positional. A positional system means that the digits in a number have different value, depending on their position. The same is not true for non-positional systems.
The most famous positional numeral system is decimal. It is the system we are using every day. It uses 10 digits (the ones from 0 to 9) and each digit has a different value in the different parts of a number. For example – 00001 is different that 10000 although the two numbers consist of the same digits.
On the other hand, an example of a non-positional numeral system is the Roman system (the one with I, V, X …). In it, the digit X has the value of 10 independently of its position in the number.
The decimal numeral system
We have been using the decimal numeral system for centuries. The reason why we have chosen it is because it is easiest for us humans to count in it as we have 10 fingers (that is the number of digits in the system as well!). Since we have used this system for such a long time, it has become so hardwired in our brains, that we don’t even realize how exactly does it work and what rules do we follow using it.
When we count in decimal, we start from 0, 1, 2 … 8, 9.. and then what? Well, since there are no more spare digits after 9, we “reset” to 0 again. But we also “carry” a digit to that 0. That way, the next number becomes 10. Then we continue until we reach 18, 19… and then again we reset to 0 but carry another digit. So the result is 20. And so on.
Now, every number in the decimal system has a value. This might seem pretty obvious, but it is so, because decimal is hardwired and we don’t realize how do we actually obtain that value. There is actually a formula for discovering the value of a number in any positional numeral system.
Let’s consider the number 123. In order to obtain the value of this number, we go through every digit of the number starting from right.
The first digit is 3 and it is in the units place. So the value of this is simply 3. Then we have 2, which is in the tens place. So the value is 2 * 10 or 20. Then we have 1 in the hundreds place. Therefore, we have 1 * 100 = 100. We sum all of this and we get 123. Expressed in a more mathy way:
1 * 100 + 2 * 10 + 3 * 1 = 100 + 20 + 3 = 123
You might notice that each time the next digit comes, it is multiplied by a number which is 10 times larger than the previous one. The same equation can be expressed this way:
1 * 10^2 + 2 * 10^1 + 1 * 10^0 (The ‘^’ symbol stands for “raised to a power of”)
Now, to generalize this for every digit in a decimal number, we get the formula:
(current digit value) * 10^(current position). For reference, the rightmost digit is at position 0, the one next to it is at position 1 and so on…
Generalizing the formula
However, this formula is applicable for numbers in any positional numeral system. The only difference is that we exchange the 10 with the base of the corresponding numeral system. So if we take the numeral system with 8 digits in it (called octal), the formula would be:
(current digit value) * 8^(current position)
For example, the number 123 in octal, would be:
(1 * 8^2) + (2 * 8^1) + (3 * 8^0) = 1 * 64 + 2 * 8 + 3 * 1 = 64 + 16 + 3 = 83 (this is the corresponding value in decimal)
Isn’t that neat? With the knowledge of how the value of decimal numbers is acquired, we have the knowledge of acquiring the value of a number in any positional numeral system.
The Binary Numeral system
The numeral system we are most interested in as computer scientists, however, is the binary system. This system shares the same rules as any other positional numeral system, but it has only two digits – 0 and 1. This means that if we want to count in binary, it will go on like this:
0, 1, 10, 11, 100, 101, 110… and so on…
It satisfies the exact same formula, which I mentioned before!
This means that you can calculate the value of any number in binary using the formula:
(current digit) * 2 ^ (the position in the number)
So, given the number 10101, we can calculate it like this:
(1 * 2^4) + (0 * 2^3) + (1 * 2^2) + (0 * 2^1) + (1 * 2^0) = 16 + 0 + 4 + 0 + 1 = 21 (in decimal)
That is how you can convert any binary number to a decimal one. But how do we go the other way around?
There is a simple algorithm for doing that, which you can derive from the formula mentioned above.
You are given the number in decimal.
- Take the remainder of division by 2 and store it somewhere
- Divide by two, but ignore the fractional part
- Do step 1 and 2 until the number is 0
- The result is all the remainders, which you stored from step 1, written in reverse order
Let’s take an example – the number 123
123 / 2 = 61 (remainder 1)
61 / 2 = 30 (remainder 1)
30 / 2 = 15 (remainder 0)
15 / 2 = 7 (remainder 1)
7 / 2 = 3 (remainder 1
3 / 2 = 1 (remainder 1)
1 / 2 = 0 (remainder 1)
Now, take the remainders in reverse order – you get the binary number 1111011
But why binary?
Why don’t computers store numbers in decimal? Won’t that be easier?
Well, that might be easier for a human, but for computers a simpler numeral system is required. The reason is that computers rely on electricity to work. That means that the digits of a number should be mapped to electricity signals. The simplest way to implement such mapping is:
0 – there is no electricity (0V)
1 – there is electricity (5V)
Why is using a more complex numeral system a problem?
Well, let’s say that we design a computer in a ternary (with 3 digits) numeral system. If we have voltage which goes from 0V to 5V, let’s say that we make the following mapping:
0 – 0V
1 – 2.5V
2 – 5V
Seems reasonable right? But imagine that I send a number across with a voltage of 2.5V. But due to some noise in the electrical circuit, I get a 2.3V on the output, so I treat it as a 0. The result?
Someone sent me a 1, but I treated it as a 0.
Loss of data can be a serious issue. Imagine sending the info of the balance on my bank account. I send 100 000 dollars, but the receiver gets 0 dollars. Not so cool, right?
In order to avoid such losses in a system like this, additional electrical components must be used in a computer in order to minimize the risk. But that could mean a more complex system, overall. That is why people use binary. It is the simplest system available and easiest to implement in an electrical circuit.
With this, I conclude the introduction to binary numbers. Now you are one step closer to becoming a better programmer and computer scientist. Next time, we will continue with our exploration of binary numbers and we shall examine how to represent negative numbers in binary.
Any thoughts on this article? Leave a comment below.