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
,并且根据Banker的舍入将转到33.3788
,这是德尔福所做的。
有人可以了解德尔福在这里做了什么吗?
答案 0 :(得分:8)
Currency
计算也会在fpu中以扩展精度进行。
您遇到的问题是浮点二进制表示,而不是舍入错误。 您可以在此处查看39.45295的浮点表示:What is the exact value of a floating-point variable?
39.45295 = + 39.45294 99999 99999 99845 67899 95771 03240 88111 51981 35375 97656 25
扩展精度值低于39.45295,因此向下舍入。
使用十进制算术库来避免这些错误。
要查看在currency
计算的fpu中执行浮点运算,这里有一个反汇编:
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
fmulp
和fdiv
以扩展精度完成。
如果使用了整数运算,则说明应为fimul
和fidiv
。