Binary Numbers and Bits: How Computers Represent Data
Everything a computer stores, from a game score to a selfie, is built out of bits: tiny values that are either 0 or 1. Programs group those bits and give each group a meaning, which is how one phone can hold numbers, letters, colors and sound. Once you can read binary, you can convert numbers by hand, compare them, and predict the mistakes a computer makes when it runs out of bits.
What are bits and bytes?
Bit is short for binary digit. A bit has only two possible values, 0 or 1. Inside a device, a bit might be a tiny switch that is off or on, a spot on a drive magnetized one way or the other, or a flash of light in a cable that is there or not there.
Computing devices represent data digitally. That means if you zoom all the way in on any value they store, a song, a message or a number, you find bits at the bottom.
A group of 8 bits is a byte. One bit can only tell two things apart, but every bit you add doubles the number of different patterns. Two bits give 4 patterns (00, 01, 10, 11), three bits give 8, and n bits give 2 to the power of n, written 2 ** n in Python.
1 bit can form 2 different patterns 2 bits can form 4 different patterns 3 bits can form 8 different patterns 4 bits can form 16 different patterns 8 bits can form 256 different patterns 16 bits can form 65,536 different patterns
A byte can form 256 patterns, enough to give a different code to every letter, digit and punctuation mark on a keyboard. That doubling also tells you how many bits you need: to give 100 things their own pattern, you need 7 bits, because 6 bits make only 64 patterns and 7 bits make 128.
How can the same bits mean different things?
Bits on their own have no meaning. A program decides what a group of bits stands for, and that is an example of abstraction: reducing complexity by focusing on the main idea. When you text a friend, you think about words, not about the thousands of bits that carry them. Abstraction hides the details that do not matter for the job at hand and brings the useful ones together into something you can work with.
Bits are grouped to represent abstractions such as numbers, characters (letters, digits, emoji) and colors. Because the meaning comes from the program, the same sequence of bits can stand for different kinds of data in different contexts. The byte 01000001 is the number 65 to a calculator. To a text app it is the capital letter A, because the standard character code used by computers gives the letter A the number 65.
Colors work the same way. Many screens describe each pixel with three bytes: how much red, green and blue light to mix, each from 0 to 255.
01000001 as a number: 65 01000001 as a letter: A 11111111 10100101 00000000 as a color: red 255, green 165, blue 0
The code also shows the places a data value can live in a program. It can be stored in a variable (bits), in a list of items (pixel), or as a constant typed straight into the code (the 2 in int(bits, 2)). Values can also be passed into a procedure as input and come back as its output: int(bits, 2) takes text in and hands a number back. (Python calls procedures [functions](/python/python-functions/).)
How does a computer store something smooth, like sound?
Analog data have values that change smoothly over time instead of jumping in steps. The temperature outside rises gradually through a morning, the sky dims a little at a time at sunset, and the speed of a bike rolling downhill changes continuously. There is always another value between any two moments.
Bits cannot hold infinitely fine detail, so devices store a close approximation. The usual method is sampling: measure the analog signal at regular intervals. Each measurement is called a sample, and it is rounded to a value that fits the number of bits set aside for one sample. A typical music file keeps 44,100 samples for every second of sound.
Standing in for real-world analog data with digital data is another example of abstraction. You keep the details that matter, enough to sound right to a human ear, and drop the rest.
t=0.0 exact=0.500 stored level=4 bits=100 t=0.8 exact=0.859 stored level=6 bits=110 t=1.6 exact=1.000 stored level=7 bits=111 t=2.4 exact=0.838 stored level=6 bits=110 t=3.2 exact=0.471 stored level=3 bits=011 t=4.0 exact=0.122 stored level=1 bits=001 t=4.8 exact=0.002 stored level=0 bits=000 t=5.6 exact=0.184 stored level=1 bits=001
The stored levels follow the shape of the wave, but they are not the exact values. Taking samples more often, or giving each sample more bits, makes the copy closer to the real thing. The cost is a bigger file.
How does binary place value work?
Data can be written in different number bases. Decimal (base 10) is the system you grew up with: it uses only the digits 0 to 9. Binary (base 2) uses only the digits 0 and 1. Both follow the same rule: a digit's position decides what it is worth.
In the decimal number 3,482, the 4 is worth 400 because it sits in the hundreds place. Positions are numbered from the right, starting at 0, and each place value is the base raised to the power of the position: 10⁰ = 1, 10¹ = 10, 10² = 100, 10³ = 1,000. A digit's value is the digit times its place value.
Binary uses base 2, so its place values are 2⁰ = 1, 2¹ = 2, 2² = 4, 2³ = 8, 2⁴ = 16, and so on. Each place is worth double the one to its right. Here is the binary number 10110:
| Position | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|
| Place value | 16 | 8 | 4 | 2 | 1 |
| Bit | 1 | 0 | 1 | 1 | 0 |
Its value is 1×16 + 0×8 + 1×4 + 1×2 + 0×1 = 22.
How do you convert binary to decimal?
Multiply each bit by its place value and add up the results. Since every bit is 0 or 1, that is the same as adding the place values that have a 1 under them. The program below does it one position at a time, starting from the rightmost bit.
position 0: 1 x 1 = 1 position 1: 0 x 2 = 0 position 2: 1 x 4 = 4 position 3: 1 x 8 = 8 position 4: 0 x 16 = 0 position 5: 1 x 32 = 32 101101 in decimal is 45
Write to_decimal(bits). It takes a binary number as a string of 0 and 1 characters and returns its decimal value as an integer. Work it out with place values instead of calling int(bits, 2), which would do the whole job for you.
to_decimal('1101') -> 13
to_decimal('0') -> 0How do you convert decimal to binary?
There are two common methods, and they always agree.
Method 1: subtract place values. List the place values up to the number (32, 16, 8, 4, 2, 1 for anything under 64). Starting from the largest, write 1 if that place value fits into what is left and subtract it, otherwise write 0. For 37: 32 fits (5 left), 16 does not, 8 does not, 4 fits (1 left), 2 does not, 1 fits. Reading the digits gives 100101. This method is quick on paper.
Method 2: divide by 2 again and again. Write down each remainder, keep dividing the quotient, and stop at 0. The remainders, read from last to first, are the bits. This method is easy to turn into a program.
37 / 2 = 18 remainder 1 18 / 2 = 9 remainder 0 9 / 2 = 4 remainder 1 4 / 2 = 2 remainder 0 2 / 2 = 1 remainder 0 1 / 2 = 0 remainder 1 37 in binary is 100101 Python's bin() agrees: 0b100101
Why does it work? The remainder after dividing by 2 says whether a number is odd (1) or even (0), and that is exactly its rightmost bit. Dividing by 2 and dropping the remainder slides every bit one place to the right, so the next remainder is the next bit. Python's built-in bin() puts 0b in front of the digits to mark them as binary.
Write to_binary(n). It takes a whole number n (0 or more) and returns its binary form as a string with no leading zeros. Use repeated division by 2 instead of bin().
to_binary(13) -> '1101'
to_binary(0) -> '0'How do you compare and order binary numbers?
To compare two binary numbers by hand, line them up so they have the same number of digits by writing zeros on the left. Leading zeros never change a value, the same way 007 is still 7. Then read from the left: the first position where the numbers differ decides, and the number with the 1 in that position is larger.
Compare 01101 and 01011. The first two digits match. In the third digit, the first number has a 1 and the second has a 0, so 01101 (13) is larger than 01011 (11). Without leading zeros, a binary number with more digits is always the larger one: 1000 (8) beats 111 (7).
Sorted as text: ['10', '1000', '1011', '111'] Sorted as numbers: ['10', '111', '1000', '1011']
Write largest_binary(numbers). It takes a list of binary numbers written as strings and returns the one with the largest value, exactly as it appears in the list (keep any leading zeros). The list always has at least one item, and no two items have the same value.
largest_binary(['101', '1000', '11']) -> '1000'Here max() on the text would wrongly pick '11'.
Check your understanding: binary
What is the decimal value of the binary number 11001?
Which binary number is equal to the decimal number 52?
Which list shows the binary numbers 1011, 110, 1101 and 111 in order from least to greatest?
What is displayed when this code segment runs?
PROCEDURE toDecimal(bitList){total ← 0FOR EACH bit IN bitList{total ← total * 2 + bit}RETURN(total)}DISPLAY(toDecimal([1, 0, 1, 1]))
What happens when a number needs more bits than it has?
In many programming languages, an integer gets a fixed number of bits, such as 8, 16, 32 or 64. That limits the range of values it can hold and the math you can do with them. With 8 bits, the biggest pattern is 11111111, which is 255. The true answer to 255 + 1 is 100000000, and that needs 9 bits. There is nowhere to put the extra bit, so the result overflows.
Depending on the language, an overflow stops the program with an error or wraps the value around and starts counting again from 0, like a two-digit stopwatch rolling from 99 to 00. Wrapping is worse in a way, because the program keeps running with a wrong answer. Here is an 8-bit coin counter in a game:
true sum 253 = 11111101 stored: 253 true sum 255 = 11111111 stored: 255 true sum 256 = 100000000 stored: 0 true sum 10 = 1010 stored: 10
The player picked up one more coin and lost 255 of them.
Other languages provide an abstraction in which integers can grow as large as the computer's memory allows. The language on the exam reference sheet works this way, so exam questions written in its pseudocode never overflow. Python works this way too:
1267650600228229401496703205376 This number needs 101 bits, and Python handles it
A sensor stores every number in a fixed number of bits and wraps around on overflow: any bits that do not fit are thrown away. Write add_fixed(a, b, num_bits) that returns the value the sensor stores after adding a and b. Both a and b already fit in num_bits bits.
add_fixed(5, 3, 4) -> 8 (8 fits in 4 bits)
add_fixed(15, 1, 4) -> 0 (16 needs 5 bits, so it wraps)Why is 0.1 + 0.2 not exactly 0.3?
Numbers with a fractional part, called real numbers (Python calls them floats), are also stored in a fixed number of bits. That limits their range and the math you can do with them, and many of them can only be stored as approximations. The value 0.1 has no exact binary form, in the same way that 1/3 has no exact decimal form (0.3333... never ends). The computer stores the closest value its bits allow, and the small difference is a round-off error. Add up enough of these and the errors show.
0.30000000000000004 False 0.9999999999999999 True
Check your understanding: what bits can and cannot do
Which of the following statements about representing data with bits are true? Select two answers.
Select 2 answers.
A game adds 0.1 to a player's speed ten times, starting from 0, and then checks whether the speed equals 1.0. The check comes out false. Which of the following best explains why?
A phone app records a singer by sampling the sound. Which change would make the recording a closer approximation of the real sound?
A school gives each of its 1,200 students a unique ID number stored in binary. What is the fewest number of bits that each ID can use?
Exam topics: 2.1 Binary Numbers (DAT-1.A, DAT-1.B, DAT-1.C)