So far we have considered that in the binary representation you have as many positions as you want. Like when you write on paper, you can always add more digits.
Now let’s consider the condition of having only a fixed number of digits. This introduces a new problem, the problem of overflow, which is what happens when you exhaust the available capacity.
Overflow occurs when the number we are trying to represent is greater than the maximum value that can be stored in the given container. In this case, the variable overflows, and returns to 0.
The problem of overflow is not unique to the binary system. It also happens, for example, if you have a combination lock with only 4 digits. When you pass 9999
, it will go back to 0000
.
In binary you will encounter the problem of overflow continuously. Because, in general, you will store your binary number somewhere in the computer’s memory. That memory has a size, and if you go over it… 💥BOOM, overflow.
On the other hand, overflow is not catastrophic “per se”. That is, your computer will not explode, nor will anything break. Simply, the number you had stored will return quietly to zero.
Of course, if you were using that number to count something… well frankly, it might not be good. If it was your WoW player level, you will start over. If it’s a plane, maybe it’s worse and it crashes to the ground.
But overflow is not bad. In fact, it is inevitable and even necessary in many processes. You just have to understand it, take it into account, and learn to control it.
Overflow Example
Unsigned overflow
Let’s imagine that we want to store the number 300
in decimal, in a binary number. But, we only have 8 bits.
The binary, the number 300
in decimal is 1 0010 1100
in binary. We would need 9 digits to store it. But since we only have 8 digits, the maximum we can store is 255 in decimal.
Therefore, if we go up, from 0 to 300, when we reach 255 the counter will reset to 0.
Let’s see it in steps:
Step | Binary | Decimal | Comment |
---|---|---|---|
0 | 0000 0000 | 0 | Start |
1 | 0000 0001 | 1 | |
2 | 0000 0010 | 2 | |
… | … | Keep going | |
255 | 1111 1111 | 255 | Reached maximum |
256 | 0000 0000 | 1 | Overflow |
… | … | Keep going | |
300 | 0010 1100 | 44 |
The stored result will be 0010 1100
in binary, which is 44 in decimal. Which is the same number as if we had converted it to binary, and removed the bits that do not fit (1 0010 1100
in this example, the 1
on the left)
Signed overflow
If the number was signed, the problem is even worse. Following the same example, let’s assume that we only have 8 bits. But now, being a signed variable, the limits are -128 to 127.
If I want to store a number 300, it’s not just that it doesn’t fit by a little… it doesn’t even fit twice in 127!
Let’s also see it in steps:
Step | Binary | Decimal | Comment |
---|---|---|---|
0 | 0000 0000 | 0 | Start |
1 | 0000 0001 | 1 | |
2 | 0000 0010 | 2 | |
… | … | Keep going | |
127 | 0111 1111 | 127 | Maximum positive |
128 | 1000 0000 | -128 | Go to negatives |
129 | 1000 0001 | -127 | |
… | … | Keep going | |
255 | 1111 1111 | -1 | Maximum negative |
256 | 0000 0000 | 0 | Overflow |
… | … | Keep going | |
300 | 0010 1100 | 44 |
Just like in the unsigned case, we ended up with a positive number 44
. But, along the way, we went through all the negatives from -128 to 0. Which, if we don’t have it under control, can be a real problem.
Overflow Handling
We have said that the most important thing is to understand overflow, and know how to manage it. Overflow is influenced by:
- The number of bits we are managing (8, 16, 32, 64…)
- If our variable is signed or unsigned.
In both cases, as we add one to our number, the binary number will increase. When it reaches the limit of its capacity, it will reset to zero.
As we have seen, it is even more complicated if the stored number represents a signed number. Because, the available range will be much smaller (half minus one), and also before overflowing, it will pass through the entire range of negative numbers.
To avoid overflowing when storing binary numbers in fixed-length containers, we have to always keep in mind the range of values expected to handle and choose the appropriate data size.
In programming environments, it is common to use specific data types (such as uint8, int16, etc.) that guarantee a valid range of values and help us prevent unwanted overflows.
In addition, when performing arithmetic operations, it is important to check the limits of the data to avoid a calculation resulting in a value outside the permitted range.