0003.h Number systems
On this page
Every earlier section of this part, from the logic gates in 0003.b to the addresses in 0003.e and the colors on a screen, rests on one representation: the bit. This section works upward through levels of granularity. It begins with why hardware uses two states at all, then shows how a row of bits counts and how many values it can hold. It then describes two ways of writing those values, binary and hexadecimal, which differ only in notation. The last part turns to meaning. The same bits can be read as a positive number, a negative number, a character, or a color, depending on the convention used to interpret them, and several of those conventions are worth knowing in detail.
Why computers use binary#
Computer hardware is built from transistors, which act as switches that are either on or off. Hardware can distinguish two states most reliably, which is why computers use binary, a system with just two digits, 0 and 1.1 The reason is physical. Electrical signals always carry some noise, small random variations in voltage. If a wire had to represent ten different levels for the ten decimal digits, the levels would be close together, and small amounts of noise would be hard to distinguish from a real signal. Two widely separated states tolerate noise far better, since a signal has to be badly distorted before "on" could be mistaken for "off." It also helps to be clear about what a bit is. The hardware holds physical states, such as a voltage being high or low, and 0 and 1 are how those states are read. Bits are the interpretation of physical states, and, as the rest of this section shows, an encoding supplies their further meaning.
Bits, bytes, and how much they can hold#
A bit is a single binary digit, 0 or 1, and a byte is 8 bits, so 3 bytes are 3 * 8, or 24, bits. The number of distinct values a group of bits can represent grows quickly: n bits represent 2^n distinct values.1 One bit has 2 values, two bits have 4 (00, 01, 10, 11), and each added bit doubles the count, since every existing pattern can be followed by either a 0 or a 1. So 4 bits store 16 values, 0 through 15, a byte has 2^8, or 256, and going from 6 bits to 7 raises the count from 64 to 128. Working backward answers the question of how many bits a set of codes needs. To give each of 300 items a distinct code, 8 bits are too few, because 2^8 is 256, while 9 bits are enough, since 2^9 is 512. The doubling also explains the scale of the move from IPv4 to IPv6 in 0003.e: 128-bit addresses give 2^128 / 2^32, or 2^96, times as many addresses as 32-bit ones.
Binary place value#
A row of bits represents a number the same way decimal digits do, by place value, except that each place is worth twice the one to its right instead of ten times. A useful picture is a row of light switches, each labeled with its place value, where the number is the total of the labels on the switches that are on. Binary is base 2, with place values of 1, 2, 4, 8, 16, 32, and so on from the right. To convert binary to decimal, add the place values where a 1 appears: 1011 is 8 + 2 + 1, or 11, and 110101 is 32 + 16 + 4 + 1, or 53. To convert decimal to binary, find which place values add up to the number. Nineteen is 16 + 2 + 1, so the 16, 2, and 1 places are on, giving 10011.1 Arithmetic works on the same principle, and converting is the simplest check: 1011 + 0110 is 11 + 6, or 17. Adding a 0 on the right doubles a number, because each digit moves to a place worth twice as much, just as adding a 0 to a decimal number multiplies it by ten.
Hexadecimal#
Long strings of bits are hard for people to read and easy to copy wrongly, so programmers often write them in hexadecimal, which is base 16. Base 16 needs sixteen digits, so after 0 to 9 it uses the letters A to F, where A is 10, B is 11, and so on up to F, which is 15. Place values are 1, 16, 256, and so on from the right. So 2F is 2 * 16 + 15, or 47, and 3C is 3 * 16 + 12, or 60. Going the other way, 42 is 2 * 16 + 10, which is 2A. One consequence can be confusing at first: 10 in hexadecimal is sixteen, not ten, because the left digit counts sixteens. Likewise, FF is 15 * 16 + 15, or 255, the largest two-digit value.
What makes hexadecimal useful is its exact fit with binary. A hexadecimal digit has sixteen possible values, and 2^4 is 16, so each hexadecimal digit corresponds to exactly four bits. Converting between the two therefore means working one digit or one four-bit group at a time, with no arithmetic on the whole number. B3 is 1011 0011, since B is 1011 and 3 is 0011, and 7D is 0111 1101, since D, which is 13, is 1101. In the other direction, 1010 0110 is A6. When the number of bits isn't a multiple of four, the groups must be formed from the right, because that is where the place values start: 101101 groups as 10 and 1101, giving 2D. Decimal digits don't line up with groups of bits in this way, which is why hexadecimal and not decimal is the usual shorthand for binary.
The same fit makes lengths easy to work out. A byte is exactly two hexadecimal digits, a 32-bit value is 32 / 4, or 8, hexadecimal digits, and a MAC address written as 12 hexadecimal digits holds 12 * 4, or 48, bits. This is why hexadecimal appears wherever people need to read long binary values: in hex dumps, which display the raw bytes of a file or of memory, in memory addresses, in hardware addresses such as a network card's MAC address, and in web colors. Everyday quantities, such as a count of students, are normally given in decimal. Notation doesn't change the stored value or its size. A value written as FF, as 255, or as 1111 1111 is the same 8 bits, and hexadecimal is chosen only because it is short and maps exactly back to bits.
Interpreting bits: colors, characters, and negative numbers#
Bits mean only what a convention says they mean, and a few conventions are common enough to know well.
A web color written as #RRGGBB gives the intensities of red, green, and blue light as two hexadecimal digits each, from 00 (none) to FF (full). The first pair is red, the middle pair is green, and the last pair is blue, so #FF0000 is pure red, #0000FF is pure blue, and #FFFFFF, all three at full intensity, is white. Halving each component darkens a color while keeping its proportions, so half of #CC6600, an orange, is #663300, a brown. Since each channel is one byte with 256 values, the number of possible colors is 256^3, about 16.7 million.
A character encoding assigns a number to each character, so text can be stored as bytes.1 ASCII uses 7 bits for basic English text, which gives 2^7, or 128, characters. In ASCII, "A" is 65 and "a" is 97. The difference between them is 32, which is 2^5, so an uppercase letter and its lowercase form differ in a single bit. ASCII has no room for most of the world's writing systems, and Unicode covers them all. Unicode text is often stored in UTF-8, a variable-length encoding that uses one to four bytes per character, so common characters such as basic English letters take one byte, the same as in ASCII, while others take more. Because the same bytes can represent different text under different encodings, bytes need a known encoding to be interpreted as text, and reading them under the wrong encoding garbles it, producing strings of odd symbols in place of accented letters.
Negative numbers need a convention too. The usual one is two's complement: to represent a negative number, take the bits of the positive number, invert every bit, and add 1.1 For -1 in 8 bits, 0000 0001 inverts to 1111 1110, and adding 1 gives 1111 1111. An 8-bit two's complement integer divides its 256 values between negative and nonnegative numbers, with a range of -128 to 127, one more negative value than positive because zero takes one of the nonnegative patterns. The fixed number of bits creates a limit. Overflow occurs when a result is too large for the bits available: in 8 bits holding values from 0 to 255, 255 + 1 needs a ninth bit, which is lost, so the result is 0. The same wraparound happens in two's complement when a result passes the largest positive value: in 8 bits, 127 + 1 becomes -128, so a counter or score that grows too large can suddenly appear as a large negative number. A wider type, one with more bits, extends the range of values that can be represented.
From transistors to colors and characters, these conventions are how a computer turns physical states into meaning. The same openness to interpretation has a cost, because anyone who can read or change the bits can read or change what they mean, and protecting those bits as they are stored and sent is the work of cybersecurity, the subject of the next part.
- binary: base 2, with place values
1,2,4,8,16, and so on from the right - bit: a single binary digit,
0or1 - byte: 8 bits, with 256 possible values
- place value: the worth of a digit's position, double the place to its right in binary and sixteen times in hexadecimal
- hexadecimal: base 16, using
0to9andAtoF, with one digit for every four bits - hex dump: a display of raw bytes in hexadecimal
- encoding: a convention that assigns meaning to patterns of bits
- web color:
#RRGGBB, the red, green, and blue intensities as two hexadecimal digits each - ASCII: a 7-bit character encoding for basic English text
- Unicode: a character set covering the world's writing systems
- UTF-8: a variable-length encoding of Unicode using one to four bytes per character
- two's complement: the usual representation of negative integers: invert the bits and add
1 - overflow: a result too large for the available number of bits
Practice: practice questions for 0003.h