我不确定这是不是一个bug,所以我想也许你们大家可能想看一看.
问题出在这个代码上:
for i=0,1,.05 do print(i) end
输出应该是:
0 .05 .1 --snip-- .95 1
相反,输出是:
0 .05 .1 --snip-- .95
while循环也发生了同样的问题:
w = 0 while w <= 1 do print(w) w = w + .05 end --output: 0 .05 .1 --snip-- .95
w的值为1,可以在循环后通过print语句验证.
我已尽可能验证任何小于或等于0.05的步骤都会产生此错误.任何高于.05的步骤应该没问题.我确认1/19(0.052631579)确实打印了1.(显然,像19.9或10.5这样的小数分母不会产生[0,1]包含的输出.)是否有可能这不是语言的错误?解释器和常规Lua文件都会产生此错误.
解决方法
这是一个四舍五入的问题.问题是0.05表示为浮点二进制数,并且它没有二进制的精确表示.在基数2(二进制)中,它是一个重复的十进制数,类似于数字,如基数为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
它会正常工作.一般情况下,建议不要使用浮点数(即带小数点的数字)来控制循环,这样可以避免.