This is a rounding issue. The problem is that 0.05 is represented as a binary floating-point number and does not have an exact representation in binary format. In base 2 (binary), this is a repeating decimal number, like digits, like 1/3 in base 10. When added repeatedly, rounding results in a number that is slightly larger than 1. This is very, very slightly larger than 1, so if you print it, 1 will be displayed as output, but it's not exactly 1.
> x=0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05 > print(x) 1 > print(1==x) false > print(x-1) 2.2204460492503e-16
So, as you can see, although really close to 1, this is actually a bit more.
A similar situation can occur in decimal when we repeat fractions. If we collected 1/3 + 1/3 + 1/3, but we had to round to six digits for work, we would add 0.333333 + 0.333333 + 0.333333 and get 0.999999, which is actually not 1. This is a similar case for binary mathematics. 1/20 cannot be represented exactly in binary format.
Note that rounding is slightly different for multiplication, so
> print(0.05*20-1) 0 > print(0.05*20==1) true
As a result, you can rewrite your code to say
for i=0,20,1 do print(i*0.05) end
And it will work correctly. In general, it is recommended that you avoid using floating point numbers (i.e. decimal point numbers) to control loops when this can be avoided.
Keith irwin
source share