Это проблема округления. Проблема в том, что 0,05 представляется в виде двоичного числа с плавающей запятой, и оно не имеет точного представления в двоичном виде. В базе 2 (двоичная) это повторяющаяся десятичная дробь, аналогичная числам типа 1/3 в базе 10. При многократном добавлении округление приводит к числу, которое немного больше 1. Это только очень, очень немного больше, чем 1 , поэтому, если вы распечатаете его, он покажет 1 как вывод, но это не точно 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
Итак, как вы можете видеть, хотя действительно близко к 1, на самом деле это немного больше.
Подобная ситуация может возникать в десятичной форме, когда у нас есть повторяющиеся дроби. Если бы мы сложили 1/3 + 1/3 + 1/3, но нам пришлось бы округлить до шести цифр для работы, мы бы добавили 0.333333 + 0.333333 + 0.333333 и получили бы 0.999999, что на самом деле не равно 1. Это аналогичный случай для двоичной математики. 1/20 не может быть точно представлена в двоичном виде.
Обратите внимание, что округление немного отличается для умножения, поэтому
> print(0.05*20-1)
0
> print(0.05*20==1)
true
В результате вы можете переписать свой код так:
for i=0,20,1 do
print(i*0.05)
end
И это будет работать правильно. В общем, желательно не использовать числа с плавающей запятой (то есть числа с десятичными точками) для управления циклами, когда этого можно избежать.