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