Home

What The Heck Is Going On Here?

The other day I came across this YouTube video:

If you've played video games long enough you might have noticed a similar effect, particularly if you are fond of "out-of-bounds" glitches or exploits where you somehow get beyond the edge of the game world and just keep going. In this article I will explain why this happens.

How Computers Store Numbers

In computers, mixed numbers are stored in floating point format. It's basically scientific notation. In base 10 scientific notation, the number 1,234 would be written as 1.234 * 103. Computers store numbers in base 2, also called binary, but the principle of precision loss is the same regardless of base. It will be easier to explain for most people reading this using base 10.

Computers only have a finite amount of space to store numbers. If you wanted to store a number in scientific notation, but you only had 6 digits for the significand and 1 digit for the exponent, then the highest number you could represent is

9 . 9 9 9 9 9 *109=9,999,990,000

Conversely, the smallest positive number that can be represented is

1 . 0 0 0 0 0 *10-9=0.000000001
You might think, that with the restriction of 6 digits for the significand and 1 digit for the exponent, that we can represent any number from 0.000000001 to 9,999,990,000, but you'd be wrong. Take for example, the number 1,234.567. In scientific notation this would be
1 . 2 3 4 5 6 7*10 3

Here's the problem. We only have 6 digits to represent the significand, but we need 7 to properly represent our number. How do we resolve this? Believe it or not, what a computer would do is just discard any extra digits at the end. So we end up throwing away the 7 and storing the number 1,234.56 instead. This is what floating point precision loss means. Look, what happens when you start with the number 1.23456 and repeatedly multiply by 10 (in other words, increase the exponent by 1).
1 . 2 3 4 5 6 *10 0=1.23456
1 . 2 3 4 5 6 *10 1=12.3456
1 . 2 3 4 5 6 *10 2=123.456
1 . 2 3 4 5 6 *10 3=1234.56
1 . 2 3 4 5 6 *10 4=12345.6
1 . 2 3 4 5 6 *10 5=123456.

Do you see it? Each time we multiply the initial number by 10 the decimal point floats to the right one place and we lose a digit for representing the fractional part of the number. When the exponent reaches 5, we have no digits left to represent fractions at all. What if we were running some program and needed to store some number in between 123,456 and 123,457? We couldn't do it, because that would require at least 7 digits in the significand! To make matters worse, consider increasing the exponent even further.

1 . 2 3 4 5 6 *10 6=1,234,560
Now, the lack of precision means we are missing the ability to store entire whole numbers like 1,234,561 and 1,234,562.

A Common Consequence of Precision Loss

A common use for floating point numbers is to represent the positions of vertices in a shape. In real life, a circle technically has infinite vertices, but in a computer shapes are made with a limited number of vertices, so a circle must have points. The impression of a circle is achieved by having enough vertices to make the edges look smooth. In the aforementioned video, the sphere is constantly moving away from the origin of the world, this means that the coordinates (although maybe not on every axis) representing the position of each vertex are increasing. As they increase, they begin to suffer from the loss of precision I showed above.

Note that it's the loss of precision that causes these visual bugs and not merely that the values of the coordinates get too high. For instance, consider the following image.
There are 3 overlapping circles each with 24 vertices. The only difference between them is the amount of decimal places reserved to store the coordinates of each vertex. Notice how merely by reducing the precision of the coordinates, the circle becomes less circular. The amount of error between two levels of precision increases dramatically as you lose more and more decimal places. Consider how close the circle with 3 decimal places is to the circle with 2 decimal places and then compare that to the one with 1 decimal place.