Lua 无法计算出 math.abs(29.7 - 30) <= 0.3 的结果。

今天早上我发现了一个我 Lua 脚本中的 bug,看起来非常奇怪。为什么这个判断会以这种方式失败呢?可以在这里测试示例。

第一个例子:

if( math.abs(29.7 - 30) <=  0.3 ) then
  result = 1
else
  result = 0
end
print("result = "..result )
-->> result = 0

第二个例子:

if( 0.3 <=  0.3 ) then
   result = 1
else
   result = 0
end
  print("result = "..result )
-->> result = 1

第三个例子:

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?

我真的很困惑,我想理解这个问题,以避免将来出现类似的 bug。谢谢。

点赞
用户2223788
用户2223788

的值为小于 1 的数。这是因为浮点数有一个精度问题。

参考: http://lua-users.org/wiki/FloatingPoint

a = 1
if a < 1 then print("<1") end

永远不会打印 "<1"。除非你实际上改变 a 的值为小于 1 的数。

2013-05-02 07:37:06
用户2195474
用户2195474

你被 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 中使用定点数。

在你的情况下,它会看起来像这样:

a = string.format("%1.1f", math.abs(29.7 - 30))
print(a == "0.3")

或者更稳健一些:

a = string.format("%1.1f", math.abs(29.7 - 30))
print(a == string.format("%1.1f", 0.3))

但是你必须确保使用的精度既适当又相同于你所有比较的精度。

2013-05-02 08:11:05