Lua fails to evaluate math.abs(29.7 - 30) <= 0.3
今天早晨,我在我的Lua脚本上发现了一个错误,但看起来很奇怪。 这种评估怎么会以这种方式失败? 例子可以在这里测试
第一个例子:
1 2 3 4 5 6 7
| if( math.abs(29.7 - 30) <= 0.3 ) then
result = 1
else
result = 0
end
print("result ="..result )
-->> result = 0 |
第二个例子:
1 2 3 4 5 6 7
| if( 0.3 <= 0.3 ) then
result = 1
else
result = 0
end
print("result ="..result )
-->> result = 1 |
第三个例子
1 2 3 4 5 6
| if( math.abs(29.7-30) == 0.3 )then
print("Lua says:"..math.abs(29.7-30).." == 0.3")
else
print("Lua says:"..math.abs(29.7-30).." ~= 0.3")
end
-->> Lua says: 0.3 ~= 0.3 WHAT? |
我真的很困惑,我想了解这一点,以避免将来出现类似的错误。 谢谢
Lua使用(IEEE 754)64位双精度浮点数这一事实使您深受打击。
看下面的例子
> print(0.3 == 0.3)
true
> print(0.3 <= 0.3)
true
> print(0.3 >= 0.3)
true
内存中0.3的实际值为:
> print(string.format("%1.64f",math.abs(-0.3)))
0.2999999999999999888977697537484345957636833190917968750000000000
现在来看您的示例:
> print(math.abs(29.7-30) == 0.3)
false
> print(math.abs(29.7-30) >= 0.3)
true
> print(math.abs(29.7-30) <= 0.3)
false
29.7-30的实际值为:
> print(string.format("%1.64f",29.7-30))
-0.3000000000000007105427357601001858711242675781250000000000000000
math.abs(29.7-30)的实际值为:
> print(string.format("%1.64f", math.abs(29.7-30))
0.3000000000000007105427357601001858711242675781250000000000000000
只是为了好玩,math.abs(-0.3)的值是:
> print(string.format("%1.64f", math.abs(-0.3)))
0.2999999999999999888977697537484345957636833190917968750000000000
有两种解决方法,第一种是阅读每位计算机科学家应该了解的关于浮点运算的知识,并理解它:-)。第二种解决方案是将Lua配置为对数字使用另一种类型,有关提示,请参见值和类型。
编辑
我只是想到了另一种"解决"问题的方法,但这有点麻烦,并且不能保证始终有效。通过首先将浮点数转换为具有固定精度的字符串,可以在lua中使用定点数字。
您的情况如下所示:
1 2
| a = string.format("%1.1f", math.abs(29.7 - 30))
print(a =="0.3") |
或更强大:
1 2
| a = string.format("%1.1f", math.abs(29.7 - 30))
print(a == string.format("%1.1f", 0.3)) |
但是,您必须确保对所有比较使用的精度都足够高且相同。
-
哦,我的上帝。我永远也不会强加于此。很好的理由。我真的很惊讶。对这项工作有什么建议吗?像这样?相比0.31?
-
我最好的建议是在我所做的编辑中,除了理解它之外,实际上没有简单的方法可以解决此问题。
-
请注意,在这种情况下,问题是要测试是否完全相等。尽管在某些情况下可以从浮点计算中获得准确的结果,但这不是其中一种。使用任意精度表示的替代方案在计算上非常昂贵,因此需要折衷。引用的文章进行了深入解释。
-
非常感谢您的提示。我当时正在做一些类似的事情来解决,但是我很高兴我走了正确的路。非常感谢另一篇非常有趣的文章。
-
Any suggestion for making this work? =>乘以10,转换为整数,使用整数,计算后除以10。
-
Lua中没有整数,因此您的建议通常不会起作用。但是,在这种情况下,只要您的结果在一定范围内(精度足够好),它就会起作用。尝试:print(string.format("%1.64f", 0.0003 * 10000))和print(string.format("%1.64f", 0.003 * 1000))。教训仍然是,如果您不希望感到惊讶,则必须了解花车。
-
"第二种解决方案是将Lua配置为对数字使用另一种类型"这将通过根本不允许浮点运算来解决问题吗?
As we know, float point has a precision problem
请参阅:http://lua-users.org/wiki/FloatingPoint
1 2
| a = 1
if a < 1 then print("<1") end |
永远不会打印"<1"。除非您实际更改a,否则不会
-
好吧,这是公理的,在我所知道的每个数字系统中,1 = 1以及因此1 < 1或1 > 1永远不可能成立。
-
是的,情况有点不同。