This tutorial will try to explain what bases are and why they are useful. This isn't a complete or perfect tutorial on bases. It's just another JK tutorial for newcomers.
Here's the definition for a few terms that are used a lot in this tutorial:
digit: Any numeral used to express a number, or the column (e.g., ones, tens) which the numeral occupies.
number: A number is an idea of an amount. You can't write a number without limiting yourself to some form of expression, but the number is the amount that exists.
numeral: Numerals are characters which aid in expressing numbers. They are not numbers in themselves, but only a form of expression for a number. For example, in decimal 10, the '1' and '0' characters are the numerals. The amount of things that the 1 and 0 represent is the number.
A base is a system of displaying a number with numerals. It is only a way of displaying the number, it does not change the number itself. For example, 100 in base 16, 256 in base 10, and 400 in base 8 are all the same number (numbers are "in" the base that is used to display them). The only thing that changed is the way the number appears.
In each base, there is a maximum value that each digit can hold before the number must use the next highest digit. In base 10, the maximum value that can be displayed in a digit is 9.
100 in base 16 is 256 in base 10 because base 16 (as its name implies) displays more values in each digit than decimal does. Because it displays 6 more values than decimal in each digit, base 16 can display the same value with lesser and often fewer numerals.
The following table gives a name for each base and lists the characters that it uses:
Although these names are based on common Latin prefixes and roots, they are not all standard names. The asterisks are used to mark the names that are more invention than standard. Hexadecimal, while being fairly standard, is not the correct name for base 16 according to the Latin system. It should have been something like sexadecimal, but was changed to use "hex" for apparent reasons.
Letters are used after the numerical character 9. Letters were chosen to represent numbers because they were easily typed and displayed by computers.
Each base's name is one greater than its highest digit value. For example, base 2 does not use a '2' because each base starts designating numbers at 0. Base 2 is called base 2 because it can display 2 values per column.
Base 10, known as decimal, is the base normally used for math. Base 10 is used instead of other bases because humans have ten fingers. And because humans learned to count with their fingers, base 10 almost seems natural.
Since you have to use a base when displaying or speaking a number, decimal is used almost everywhere. Other bases are named (e.g., base 16) according to the decimal display of the number of values per digit that the base uses. Base 16 wouldn't be called "base 16" if everyone used it. It would be called "base 10" because the base's name is the max number of values per digit plus one. And in hexadecimal or any other base, that number will be 10.
In the text above, this tutorial says that base 10 should almost seem natural. So why wouldn't it be completely natural? Because your hands can use base 11. Your hands can display any number from 0 to 10 which is what base 11 does. Base 10 cannot display 10 values with one digit.
In mathmatics, you'll carry over to the next digit when you can't display anything greater in that digit with the base you're using. But you won't when counting on your fingers. You can display 10 by holding out all of your fingers or by holding out one finger if you are counting in tens.
In decimal math, there is no inbetween '10' character for the first digit. You'll get to 9 and then carry over. But when counting on your fingers, you'll get to 9, and then you can carry over or hold out your tenth finger.
Higher bases can display the same numbers as lower bases, but with fewer digits and lesser numerals. For example, 100 in base 16 is 256 in decimal. This is because digits in base 16 are worth more than digits in base 10.
Why? Because base 16 has to count through more digit values before it carries over to the next digit. For example, one less than 100 in base 16 is FF. Decimal does not display so many values per digit, so it carries over when it reaches 9. Hexadecimal goes up to F before it carries over to the next greater digit.
Before going on to base conversions, take a look at the decimal power of each digit. Here's a table with the more common bases:
|Base||Digit 0||Digit 1||Digit 2|
|Binary||1 (20)||2 (21)||4 (22)|
|Octal||1 (80)||8 (81)||64 (82)|
|Decimal||1 (100)||10 (101)||100 (102)|
|Hexadecimal||1 (160)||16 (161)||256 (162)|
The decimal value of each digit in a base is determined by finding baseNum to the power of digitNum. For example, if baseNum were 16 for hexadecimal, and digitNum were 2 for the third digit, the decimal eqivalent of a 1 in digit 2 would be 256. That is, the value of a 1 in hexadecimal's digit 2 would be the same as 256 in decimal. This provides us with a tool for conversion to and from decimal.
But we're using decimal to do the math, so the conversion can only be used with decimal numbers. If we were to use other bases with this conversion system, we would have to make another table.
The typical approach would be to pop out the Windows calculator to convert your number. But the problem is Real Programmers don't use calculators. So you'll just have to learn how to convert numbers between bases.
When converting from one base to another, decimal (being ingrained) will be the base that is used to do the math. So you'll be converting from one base to decimal and then to another base if you need.
Some simple conversions from octal to decimal using the chart above:
Convert the octal number 25 to decimal:
For digit 1: 2 * 8 = 16. Add 16 to our result. For digit 0: 5 * 1 = 5. Add 5 to our result. The result is: 21.
Each digit was multiplied by its decimal value from the chart above. Then the products were added to find the result. To convert back to octal:
Convert the decimal number 21 to octal:
There are no 64's in our number. There are two 8's in our number. Add 20 to our result. There is a remainder of 21-16=5. There are five 1's left. Add 5 to our result. The result is: 25.
This example went through each octal digit in our chart from greatest to least. There were two 8's in the number. Because of these two 8's, two 10's were added to the result because 10 is decimal's value for digit 1 and the 8 is octal's value for digit 1. Now to do a conversion from decimal to binary:
Convert the decimal number 13 to binary:
There are no 16's in our number. There is one 8 in our number. Add 1000 to our result. There is a remainder of 13-8=5. There is one 4 in our number. Add 100 to our result. There is a remainder of 5-4=1. There are no 2's in our number. There is one 1 in our number. Add 1 to our result. The result is: 1101.
That example used some binary digits not on our chart, but you can find that the numbers for binary digits 3 and 4 are 8 and 16 respectively. Now to convert back to decimal:
Convert the binary 1101 to decimal:
For digit 3: 1 * 8 = 8. Add 8 to our result. For digit 2: 1 * 4 = 4. Add 4 to our result. No value for digit 1. For digit 0: 1 * 1 = 1. Add 1 to our result. The result is: 13.
Now, to do a more complicated hexadecimal to decimal conversion in slightly different form.
Convert the hexadecimal 2EA.F to decimal:
result = (2 * 162) + (14 * 161) + (10 * 160) + (15 * 16-1) result = (512) + (224) + (10) + (15/16) result = 746 + 0.9375 result = 746.9375
A decimal point was used in the hexadecimal number, but floating-point numbers are covered later on. Also, 16 to the power of -1 is the same as 1/16. Now to convert the number back to hexadecimal.
Convert the decimal number 746.9375 to hexadecimal:
First the 746: There are two 256's in our number. Add 200 to our result. There is a remainder of 746-512=234. There are fourteen 16's in our number. Add E0 to our result. There is a remainder of 10. There are ten 1's left in our number. Add A to our result. The result is now: 2EA. Now the fractional portion: result2 = 9375/10000 result2 = 15/16 (reduced) There are fifteen 1/16's in our number. Add 0.F to our result. The result is 2EA.F.
There are several important things in this example. Because a hexadecimal digit can hold a higher value than a decimal digit, having ten 1s and fourteen 16s is reasonable. Because fractions in hexadecimal are in sixteenths instead of tenths as in decimal, 15/16 is the same as 0.F. It's just like having 9/10 in decimal - it's the same as 0.9.
For computing purposes, hexadecimal, octal, and binary are often used. Hexadecimal is useful in computer science because it represents numbers in a compact form and it is easily converted to and from binary. With four bits, you can store any hexadecimal character from 0 to F:
Hexadecimal can represent the same value in much less space than binary and decimal. Each hexadecimal number is represented by four bits (called a nybble). This makes hexadecimal useful for displaying memory values in an efficient form.
Hexadecimal is also useful for storing up to four boolean values in a digit. For example, any addition of 1, 2, 4, or 8 yields a number with known components. For example, 3=1+2, F=8+4+2+1, E=4+8+2, 9=8+1. Any combination results in a number that can be decomposed into the numbers that add up to it. If you look at the table above, you'll see why (1, 2, 4, and 8 use separate bits). This makes hexadecimal useful for cog flags.
Hexadecimal can be easily converted to and from binary in a more simple method than the examples used. With the table above, you can convert a binary number of four bits into hexadecimal. For example, the number 11110011 is F3. Just seperate the binary number into nybbles and use the table above to find the hexadecimal equivalent.
Octal is similar to hexadecimal in that it is used for some of the same reasons. It's maximum digit value is 7 which is represented in binary as 111. Only three bits are needed to store an octal digit. Like hexadecimal, it is easily converted to and from binary - instead of nybbles, use groups of three bits.
Binary is extremely useful to computers because values of 0 and 1 - true and false - are easy to store and transfer. The downside is that they are much less efficient in terms of the space that it takes to store and display so many digits. For example, 9 in decimal is 1001 in binary.
As explained above, using a different base does not change the number you're displaying. It only changes the form that it's shown in. When writing numbers, especially in your code, you must specify the base of a number if it's not in decimal.
Say you used the number 100 in your code. When the interpreter/compiler/parser reads that, it will assume that the number is in decimal. To tell the parser what base the number is in, there are two standard prefixes to put before a number. These are '0x' for hexadecimal and '0' for octal.
If you want to write a hexadecimal 100, you would write 0x100. Or if you wanted to write 100 in octal, you would write 0100. Other bases will have to be converted. Not all parsers support these prefixes, but Cog, being based on C++, does support them.
A floating-point number (a float) uses a radix point (a decimal point in base 10) and numerals to its right to display the fractional portion of the number.
A hexadecimal or octal number can have a fractional part just as base 10 numbers do, but this is hardly ever done. Since there isn't much of a reason to have a floating-point number in anything but base 10, other bases are usually restricted to being whole numbers. Not even the Windows calculator allows floating-point numbers in non-decimal bases.