Introduction to numerical bases
We all used to count in base 10 (decimal) system - since we got 10 fingers on our hands, so historically - that’s what happened. I suppose if we were evolved with another finger, our convenient numeric base would change accordingly.
Surprisingly, computers don’t have any fingers at all, so it’s not natural for them to count in our base, it could be, but they weren’t made that way (at least not the common ones that you use on a daily basis) - there are many reasons for that, which will not be covered in this article.
Number is a mathematical term which can be represented in different bases, however that doesn’t affect the number itself, it's just a way of representing it.
Similarly, the word "Bean" is represented in English and in other languages differently, but this doesn’t change the meaning of the word “Bean”.
Wiki:
https://en.wikipedia.org/wiki/Numerical_digit
When you are working with numbers in different bases, you will need to note explicitly the base of the number to avoid the confusion, since the same graphic symbol can represent a completely different number:
Example for different bases with same graphical digits:
11 - in decimal means : 11
11 - in octal means: 9
11 - in hex means : 17
In our daily lives we use base 10 by default, so there is no need to mention the base type.
In base 10 (decimal) each numbers’ digit represents a base 10 number from 0 to 9 (10 digits).
- From now on, I will use the word index when I am talking about the place of a digit in our number (counting from the right to left), while the first index is 0 (zero based index), for example:
Decimal number 4687(decimal) -
the number “7” on the 0 index in our decimal .
the number “8” on the 1<sup>st</sup> index in our decimal .
the number “6” on the 2<sup>nd</sup> index in our decimal .
the number “4” on the 3<sup>rd</sup> index in our decimal .
- Each digits’ value in a number is a set of the index to the bower of base, times the digit value (if you are confused don’t worry, we’ll examine it by examples…)
Let’s split the number 4687(decimal) to its digits:
7 represents 7 times 10 in power of 0 = 7 * 10 ^ 0 = 7 * 1 = 7
8 represents 8 times 10 in power of 1 = 8 * 10 ^ 1 = 8 *10 = 80
6 represents 6 times 10 in power of 2 = 6 * 10 ^ 2 = 6 * 100 = 600
4 represents 4 times 10 in power of 3 = 4 * 10 ^ 3 = 4 * 1000 = 4000
Result
: 4000 + 600 + 80 + 7 = 4687
If you’ll count to ten (starting from 0) you will get something like this:
0,1,2,3,4,5,6,7,8,9,10
See what happened after we added 1 to 9?
We started counting with one digit - 0, and then each time we added 1 to our number.
As our number became equal to the base value (10) we had an overflow – se we carried 1 to a new index (1nd index) - which makes our number: 1 * 10 + 0 * 0 = 10.
Let's continue counting until we set a new index in our decimal:
10,11,12,13,14,15,16,17,18,19,20
Same idea here: the only difference is, that we already had 1 on our 1st index, so we added 1 to that index until we got to 20 (decimal) - which is the power of our base (20 = base * 2):
20(decimal) = 2 * (10 ^ 1) + 0 * (10 ^ 1)= 20 * 10 + 0 * 10 = 20 + 0 = 20
Another example:
If we'll pick up another random decimal number: 12345.
First index range: 0 – 9
Second index range: 10– 19
Third index range: 20– 29
And so on…
Let’s take another look at our number, we’ll split it by indexes and configure the actual meaning of the number:
Our number is 12345, let’s split it to indexes:
5 – 1st index, 4 – 2nd index, 3 – 3rd index, 2 – 4th index, 1 – 5th index
Now we can calculate the number mathematically:
12345 = (5 * 10^0) + (4 *10^1) + (3 *10 ^2) + (2 *10 ^3) + (1*10 ^4) =
= (5 * 1) + (4 *10) + (3 *100) + (2 *1000) + (1*10 ^10000) = 123245
We are so used to decimal numbers that we are doing those calculations automatically, but if you would to remember you first steps in math lessons you’d probably realize that that’s the way you’ve done it.
0 = 0 * (10 ^ 0)
1 = 1 * (10 ^ 0)
2 = 2 * (10 ^ 0)
3 = 3 * (10 ^ 0)
4 = 5 * (10 ^ 0)
5 = 6 * (10 ^ 0)
6 = 7 * (10 ^ 0)
7 = 7 * (10 ^ 0)
8 = 8 * (10 ^ 0)
9 = 9 * (10 ^ 0)
10 = 0 * (0 ^ 10) + 1 * (10 ^ 1)
11 = 1 * (0 ^ 10) + 1 * (10 ^ 1)
12 = 2 * (0 ^ 10) + 1 * (10 ^ 1)
13 = 3 * (0 ^ 10) + 1 * (10 ^ 1)
14 = 4 * (0 ^ 10) + 1 * (10 ^ 1)
15 = 5 * (0 ^ 10) + 1 * (10 ^ 1)
16 = 6 * (0 ^ 10) + 1 * (10 ^ 1)
17 = 7 * (0 ^ 10) + 1 * (10 ^ 1)
18 = 8 * (0 ^ 10) + 1 * (10 ^ 1)
19 = 9 * (0 ^ 10) + 1 * (10 ^ 1)
20 = 0 * (0 ^ 10) + 2 * (10 ^ 1)
After we covered the decimal base and the base convention, we can move on to other bases.
Computers are powered by electricity, so in order to communicate with them, we need to translate our (human) data to electrical signals.
Electrical signal can be converted to 0’s and 1’s as:
1 – Electricity is on.
0 - Electricity is off.
We can say that 0 is any voltage less than X, and 1 is any voltage above X (2 states). If we would use a decimal number we would need to define a more complex model - since we need to define 10 states (for each digit).
There were attempts for making decimal computers, and others bases, but eventually the standard became a binary base.
Computer with different numerical bases:
Decimal computer:
https://en.wikipedia.org/wiki/Decimal_computer
Trenary computer:
https://en.wikipedia.org/wiki/Ternary_computer
You can use different techniques, but in my opinion the easiest way to convert decimal to binary (without a calculator’s help) is to simply iterate over the binary indexes and assemble your desired number, as follows:
Lest take a decimal number: 19
First I’ll just enumerate the indexes of binary digits.
x is the digit on the index - in binary case, can be 0 or 1.
0 index = (2^0) * x = 1 * x
1 index = (2^1) * x = 2 * x
2 index = (2^2) * x = 4 * x
3 index = (2^3) * x = 8 * x
4 index = (2^4) * x = 16 * x
5 index = (2^5) * x = 32 * x
32 16 8 4 2 0
Now we’ll iterate over the indexes and try to find a number that fits our decimal:
Reminder: our number is 19
You can see that 32 is bigger than our number, so it cannot represent it.
16 is suitable since it’s less than 19, so let’s mark it up: 10000 (binary)
We’re left with: 19 - 16 = 3
Now we need to represent 3 in binary - let's iterate once again with what’s left:
4 2 0
4 is too large… So we’ll pick up 2 - let’s mark it
10010
We’re left with 19 - 16 - 2 = 1 and it’s obviously - 1(binary)
Let’s assemble our marks: 10011
19 (decimal) = 10011(binary)
When converting from binary to decimal we use the same principles as we use in decimals:
10011 = 1 * (2^ 0) + 1* (2 ^1) + 1 * (2 ^ 4) =1 + 2 + 16 = 19
0 = 0 * (2 ^ 0) = 0 (decimal)
1 = 1 * (2 ^ 0) = 1 (decimal)
10 = 1 * (2 ^ 0) + 0 * (2 ^ 0) = 2 (decimal)
11 = 1 * (2 ^ 0) + 1 * (2 ^ 1) = 3 (deximal)
100 = 0 * (2 ^ 0) + 0 * (2 ^ 1) + 1 * (2 ^ 2) = 4 (decimal)
101 = 1 * (2 ^ 0) + 0 * (2 ^ 1) + 1 * (2 ^ 2) = 5 (decimal)
110 = 0 * (2 ^ 0) + 1 * (2 ^ 1) + 1 * (2 ^ 2) = 6 (decimal)
111 = 1 * (2 ^ 0) + 1 * (2 ^ 1) + 1 * (2 ^ 2) = 7 (decimal)
1000 = 0 * (2 ^ 0) + 0 * (2 ^ 1) + 0 * (2 ^ 2) + 1 * ( 2 ^ 3) = 8 (decimal)
1001 = 1 * (2 ^ 0) + 0 * (2 ^ 1) + 0 * (2 ^ 2) + 1 * ( 2 ^ 3) = 9 (decimal)
1010 = 0 * (2 ^ 0) + 1 * (2 ^ 1) + 0 * (2 ^ 2) + 1 * ( 2 ^ 3) = 10 (decimal)
1011 = 1 * (2 ^ 0) + 1 * (2 ^ 1) + 0 * (2 ^ 2) + 1 * ( 2 ^ 3) = 11 (decimal)
1100 = 0 * (2 ^ 0) + 0 * (2 ^ 1) + 1 * (2 ^ 2) + 1 * ( 2 ^ 3) = 12 (decimal)
1101 = 1 * (2 ^ 0) + 0 * (2 ^ 1) + 1 * (2 ^ 2) + 1 * ( 2 ^ 3) = 13 (decimal)
1110 = 0 * (2 ^ 0) + 1 * (2 ^ 1) + 1 * (2 ^ 2) + 1 * ( 2 ^ 3) = 14 (decimal)
1111 = 1 * (2 ^ 0) + 1 * (2 ^ 1) + 1 * (2 ^ 2) + 1 * ( 2 ^ 3) = 15 (decimal)
10000 = 0 * (2 ^ 0) + 0 * (2 ^ 1) + 0 * (2 ^ 2) + 0 * ( 2 ^ 3) + 1 * ( 2 ^ 4)= 16 (decimal)
10001 = 1 * (2 ^ 0) + 0 * (2 ^ 1) + 0 * (2 ^ 2) + 0 * ( 2 ^ 3) + 1 * ( 2 ^ 4)= 17 (decimal)
10010 = 0 * (2 ^ 0) + 1 * (2 ^ 1) + 0 * (2 ^ 2) + 0 * ( 2 ^ 3) + 1 * ( 2 ^ 4)= 18 (decimal)
10011 = 1 * (2 ^ 0) + 1 * (2 ^ 1) + 0 * (2 ^ 2) + 0 * ( 2 ^ 3) + 1 * ( 2 ^ 4)= 19 (decimal)
10100 = 0 * (2 ^ 0) + 0 * (2 ^ 1) + 1 * (2 ^ 2) + 0 * ( 2 ^ 3) + 1 * ( 2 ^ 4)= 19 (decimal)
Hex (base 16 )
Hexadecimal is a 16 base number - hexa (six) + decimal (ten), which can be used to represent a large binary number in more humanly readable way.
Since it’s base 16, as in binary and decimals, one digit can represent 0 to 15 decimal value.
Numbers larger than 9 (in decimal base) are represented by two digits, in hexadecimal base we write them as characters to avoid confusion.
One Hex digit binary range: 0000 - 1111 (4 bits)
One hex digit decimal range:
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Binary data of 4 bits can be represented only by one Hex character, so if we’ll look at a binary “large” data example:
32 bit binary number: 00010000000100001111000011111011
You can notice that it's not really readable (at least at first glance).
Let’s convert it to hex:
We’ll separate the large binary into a groups of four (since it’s the hex digit range) and for each binary group we’ll assign an appropriate hex digit:
0001 - 1 (hex) - 1 (decimal)
0000 - 0 (hex) - 0 (decimal)
0001 - 1 (hex) - 1 (decimal)
0000 - 0 (hex) - 0 (decimal)
1111 - F (hex) - 15 (decimal)
0000 - 0 (hex) - 0 (decimal)
1111 - F (hex) - 15 (decimal)
1010 - B (hex) - 11 (decimal)
Assembling all our conversions, we get - 1010F0FB (269545723 in decimal)
-
Hex numbers are always written with hex prefix - 0x, in our case : 0x1010F0FB
-
Hex numbers are commonly used in computers, whenever working with binaries – use HEX.
0 = 0 * (16 ^ 0) = 0 (binary) = 0 (decimal)
1 = 1 * (16 ^ 0) = 1 (binary) = 1 (decimal)
2 = 2 * (16 ^ 0) = 10 (binary) = 2(decimal)
3 = 3 * (16 ^ 0) = 11 (binary) = 3(decimal)
4 = 4 * (16 ^ 0) = 100(binary) = 4(decimal)
5 = 5 * (16 ^ 0) = 101(binary) = 5(decimal)
6 = 6 * (16 ^ 0) = 110(binary) = 6 (decimal)
7 = 7 * (16 ^ 0) = 111(binary) = 7(decimal)
8 = 8 * (16 ^ 0) = 1000(binary) = 8(decimal)
9 = 9 * (16 ^ 0) = 1001(binary) = 9(decimal)
A = 10 * (16 ^ 0) = 1010(binary) = 10(decimal)
B = 11 * (16 ^ 0) = 1011(binary) = 11(decimal)
C = 12 * (16 ^ 0) = 1100(binary) = 12(decimal)
D = 13 * (16 ^ 0) = 1101(binary) = 13(decimal)
E = 14 * (16 ^ 0) = 1110(binary) = 14(decimal)
F = 15 * (16 ^ 0) = 1111(binary) = 15(decimal)
10= 0 * (16 ^ 0) + 1 * (16 ^ 1) = 10000(binary)= 16(decimal)
11= 1 * (16 ^ 0) + 1 * (16 ^ 1) = 10001(binary)= 17(decimal)
12= 2 * (16 ^ 0) + 1 * (16 ^ 1) = 10010(binary)= 18(decimal)
13= 3 * (16 ^ 0) + 1 * (16 ^ 1) = 10011(binary)= 19(decimal)
14= 4 * (16 ^ 0) + 1 * (16 ^ 1) = 10100(binary)= 20(decimal)
Octal is a base 8 numerical system, which uses the digits 0 to 7.
Using octal numbers is an easier way of representing binary numbers.
If you’ll take any binary number and divide it in groups of three you will get groups of numbers that can be easily reinterpreted as decimals:
Example: 100001111001 -> 100 001 111 001 -> 4 1 7 1 = 2169
Octal base can still pop up in some places, but it’s not that common today...
Notice that 8 and 16 are both powers of 2:
2^3 = 8, 2^4 = 16.
That’s why octal binary range is from 000 - 111 and hex is 0000-1111 because adding another index to binary numbers, multiplies its value by 2 , in programing that kind of operation is called binary shifting.
Octals on Wiki:
https://en.wikipedia.org/wiki/Octal
One octal sign decimal range:
0 1 2 3 4 5 6 7
So if we’ll take a decimal number - 192
we can write it as 300 in octal, again with the same principles that we used in our previous hex bases:
300 = 0 * (8^ 0) + 0 * (8^ 1) + 3 * (8 ^2) = 0 * 0 + 0 * 8 + 3 * 64 = 3 * 64 = 192
0 = 0 * (8 ^ 0) = 0 (binary) = 0 (decimal)
1 = 1 * (8 ^ 0) = 1 (binary) = 1 (decimal)
2 = 2 * (8 ^ 0) = 10 (binary) = 2(decimal)
3 = 3 * (8 ^ 0) = 11 (binary) = 3(decimal)
4 = 4 * (8 ^ 0) = 100(binary) = 4(decimal)
5 = 5 * (8 ^ 0) = 101(binary) = 5(decimal)
6 = 6 * (8 ^ 0) = 110(binary) = 6 (decimal)
7 = 7 * (8 ^ 0) = 111(binary) = 7(decimal)
10 = 0 * (1 ^ 8) + 1 * (1 ^ 8) = 1000(binary) = 8(decimal)
11 = 1 * (1 ^ 8) + 1 * (1 ^ 8) = 1001(binary) = 9(decimal)
12 = 2 * (1 ^ 8) + 1 * (1 ^ 8) = 1010(binary) = 10(decimal)
13 = 3 * (1 ^ 8) + 1 * (1 ^ 8) = 1011(binary) = 11(decimal)
14 = 4 * (1 ^ 8) + 1 * (1 ^ 8) = 1100(binary) = 12(decimal)
15 = 5 * (1 ^ 8) + 1 * (1 ^ 8) = 1101(binary) = 13(decimal)
16 = 6 * (1 ^ 8) + 1 * (1 ^ 8) = 1110(binary) = 14(decimal)
17 = 7 * (1 ^ 8) + 1 * (1 ^ 8) = 1111(binary) = 15(decimal)
20 = 0 * (1 ^ 8) + 2 * (1 ^ 8) = 10000(binary)= 16(decimal)
21 = 1 * (1 ^ 8) + 2 * (1 ^ 8) = 10001(binary)= 17(decimal)
22 = 2 * (1 ^ 8) + 2 * (1 ^ 8) = 10010(binary)= 18(decimal)
23 = 3 * (1 ^ 8) + 2 * (1 ^ 8) = 10011(binary)= 19(decimal)
24 = 4 * (1 ^ 8) + 2 * (1 ^ 8) = 10100(binary)= 20(decimal)
Octal numbers are used in Unix file permissions, for example when you call chmod command you are specifying the permission by octal number:
chmod 754 myfile.temp
That command will change the file named - “myfile.temp”’ permissions appropriately.
Unix permissions in a nutshell
4 stands for "read",
2 stands for "write",nds for "execute", and
0 stands for "no permission."
So, in our case:
7 stands for combination of : 4 +2 + 1 (read, write, and execute)
5 stands for combination of : 4 + 1 (read, execute)
4 stands for 4 (read)
There are three groups: World, Group and User. Each octal digit in our chmod command represents the permission for one of them.
1st - user, 2nd - group, 3rd - others(world)
Converting from one base to another is pretty easy when you understand how numeric bases work, however,
in programing you’ll probably encounter the hexes more than other bases since it is more common.