The infinite loop is due to the inexact way computers represent floating-point numbers.
A computer can dedicate only a certain number of bits to each variable. You can think of this as storing a limited number of digits after the decimal place. In base ten you can represent 1/10 exactly as 0.1, so you can write d
with perfect precision as it progresses through 0.0, 0.1, 0.2, ..., 10.0. But imagine incrementing by 1/7. This is a repeating decimal (0.142857142857...)
and therefore cannot be represented precisely in base 10 with a limited number of digits. If the computer could store only 2 decimal places for each variable, then d
would look something like this:
Fraction Actual Value Stored Value
1/7 0.142857... 0.14
2/7 0.285714... 0.28
3/7 0.428571... 0.42
4/7 0.571428... 0.56 ← mismatch
5/7 0.714285... 0.70
6/7 0.857142... 0.84
7/7 1.0 0.99
Note the rounding errors in every value from 4/7 onward. (Actually, every value has a rounding error due to truncation; it's just more obvious when the digits don't match.) The important thing to notice is that it doesn't matter how many digits we store; unless it's infinite, there will always be a rounding error.
So, in base ten, incrementing a variable by 0.1 is simple and "clean" because the number can be represented exactly with a limited number of digits. But that's not the case for numbers that are represented by repeating decimals, like 1/6, 1/7, 1/13, and so on.
Computers store numbers in binary (base 2), but the concept is exactly the same. The fraction 1/10 does not have an exact representation in base 2. The computer must represent every number by adding together different powers of 2: numbers like 8, 4, 2, 1, ½ ¼, ⅛, and so on. For example:
15 = 8 + 4 + 2 + 1 = 1111b
10 = 8 + 0 + 2 + 0 = 1010b
2½ = 0 + 0 + 2 + 0 + ½ = 0010.1b
¾ = 0 + 0 + 0 + 0 + ½ + ¼ = 0010.11b
But we can't represent 1/10 exactly using only powers of 2:
1/10 = 0/2 + 0/4 + 0/8 + 1/16 + 1/32 + 0/64 + 0/128 + 1/256 +
1/512 + 0/1024 + 0/2048 + 1/4096 + 1/8192 + ...
1/10 = 0.0001100110011...b
Again, imagine we have a limited number of decimal places. You'll see that no matter how many we use, we'll eventually generate a rounding error if we continue to add 1/10. And that's exactly what happens in your program: repeatedly adding the binary representation of 1/10 will generate a rounding error before the sum reaches 10.0, so the condition d != 10.0
will always be true.
Because of this, when working with floating-point numbers, the best practice is as several others suggested: never test floating-point variables for equality; always use inequalities. You can eliminate the infinite loop with while (d < 10.0)
.