微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

德尔福如何在乘法过程中舍入货币

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,这就是德尔福所做的.

有人可以了解德尔福在这里做了什么吗?

解决方法

即使货币本身是64位整数值,货币计算也会在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,因此向下舍入.

使用十进制算术库来避免这些错误.

要查看在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.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐