2013-05-02 58 views
3

今天早上我發現了一個我的Lua腳本上的錯誤,這看起來很奇怪。這種評估如何以這種方式失敗?例子可以在hereLua未能評估math.abs(29.7 - 30)<= 0.3

第一個例子進行測試:

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? 

我真的很迷惑,我想明白這樣可以避免將來出現類似的錯誤。由於

回答

8

你受到了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

有兩種解決方案你親第一個是What Every Computer Scientist Should Know About Floating-Point Arithmetic,理解它:-)。第二個解決方案是將Lua配置爲使用其他類型的數字,請參閱Values and Types提示。

編輯 我只是想到了另一種「解決」問題的方式,但它有點破解,而且不保證總能正常工作。您可以在lua中使用固定點數字,首先將float轉換爲具有固定精度的字符串。

在你的情況,將是這個樣子:

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)) 

但是你必須確保你使用的精度,既充分和相同所有你比較。

+0

哦,我的上帝。我從來沒有這樣做過。非常好的理由。我真的很驚訝。任何建議使這項工作?喜歡這個? 對比0.31? – MRodrigues 2013-05-02 08:26:31

+1

我的最佳建議是在我編輯的編輯中,除了理解它之外,沒有簡單的解決方法。 – jbr 2013-05-02 08:32:05

+2

請注意,這是一個問題是測試精確相等的情況。雖然有些情況下您可以從浮點計算得到準確的結果,但這不是其中的一種情況。使用任意精度表示的替代方案在計算上非常昂貴,因此需要妥協。引用的文章深入解釋。 – RBerteig 2013-05-02 09:04:12

0

我們知道,浮點數有精度問題

參見:http://lua-users.org/wiki/FloatingPoint

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

不打算打印"<1"。除非你真的改變a

+0

那麼這是公理的,在我知道的每個數字系統中,'1 = 1'因此''永遠不會是真的。 – jbr 2013-05-02 08:14:00

+0

是的,這是一個有點不同的情況。 – MRodrigues 2013-05-02 08:29:34