2016-09-30 49 views
4
rate : Currency; 
mod1 : Currency; 
mod2 : Currency; 
mod_rate : Currency; 

rate := 29.90; 
mod1 := 0.95; 
mod2 := 1.39; 

mod_rate := rate * mod1 * mod2; 

如果您在計算器上執行此計算,您將得到一個值39.45295。由於Delphi的Currency數據類型僅精確到4位小數,因此它在內部舍入值。我的測試表明它使用Banker的四捨五入,因此mod_rate應該包含值39.4530,但是在這種特殊情況下,它會截斷爲39.4529德爾福如何在乘法運算中循環貨幣

我有40,000這些計算,除了上面所有都是正確的。下面是圍捕的例子:

rate := 32.25; 
mod1 := 0.90; 
mod2 := 1.15; 

這在計算器上等於33.37875並根據銀行家舍入將歸33.3788,這是德爾福做什麼。

難道有人會對德爾福在這裏做的事情有所瞭解嗎?

+0

我的猜測是39.4595在浮點上不能完全表示。四捨五入沒有錯,但具有可代表性。使用十進制算術代替貨幣。 –

+0

貨幣是一個固定點數據類型。除非乘以兩個貨幣產生浮動。 – Chet

+0

@Chet:'貨幣'值在內部存儲爲64位整數,乘以10000以除去小數,但對「貨幣」值執行的數學運算使用這些整數上的浮點數學指令。 –

回答

8

Currency計算髮生在擴展精度的fpu中,即使貨幣本身是一個64位整數值。

您遇到的問題是浮點二進制表示,而不是舍入錯誤。 可以看到的39.45295浮點表示這裏:​​

39.45295 = + 39.45294 99999 99999 99845 67899 95771 03240 88111 51981 35375 97656 25

的擴展精度值低於39.45295,因此向下四捨五入。

改用十進制算術庫來避免這類錯誤。


地看到,浮點運算在FPU爲currency計算進行,這裏是一個拆解:

mod_rate := rate * mod1 * mod2; 
0041D566 DF2D20584200  fild qword ptr [$00425820] 
0041D56C DF2D28584200  fild qword ptr [$00425828] 
0041D572 DEC9    fmulp st(1) 
0041D574 DF2D30584200  fild qword ptr [$00425830] 
0041D57A DEC9    fmulp st(1) 
0041D57C D835C4D54100  fdiv dword ptr [$0041d5c4] 
0041D582 DF3D38584200  fistp qword ptr [$00425838] 
0041D588 9B    wait 

fmulpfdiv與擴展精度完成。 如果使用了整數運算,說明應該是fimulfidiv

+0

我準備好接受這個答案。你能否引用一些表明Delphi將Currency作爲浮點的文檔? – Chet

+0

是的,我打算分析組件來驗證,謝謝發佈。 – Chet

+0

801/2(兩種貨幣)的結果爲400.5。根據這個(http://pages.cs.wisc.edu/~rkennedy/exact-float?number=400.5),可以用浮點數表示。然而,這可能會達到401.我相信這仍然是一個計劃生育問題,但它很煩人。 – Chet