2014-09-02 51 views
2

我这是将62到61舍入并将其显示在输出中的代码。为什么它决定整合以及如何获得62的输出?double rounding

var d: double; 
i: integer; 
begin 
    d:=0.62; 
    i:= trunc(d*100); 
    Showmessage(inttostr(i)); 

end; 
+0

可能重复[浮点数学是否被破坏?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Mark 2016-04-04 13:43:32

回答

13

这归结为0.62在二进制浮点数据类型中不能完全表示的事实。该closest representable double value to 0.62是:

 
0.61999 99999 99999 99555 91079 01499 37383 83054 73327 63671 875 

当你乘以100这个值,结果值略小于62.接下来会发生什么取决于如何中间值d*100进行处理。在您的程序中,使用默认设置的32位Windows编译器下,中间值保存在80位扩展寄存器中。与最接近的80位扩展精度值为:

 
61.99999 99999 99999 55591 07901 49937 38383 05473 32763 67187 5 

由于该值小于62,返回Trunc 61自Trunc轮朝向零。

如果您将d*100存储为double值,则会看到不同的结果。

d := 0.62; 
d := d*100; 
i := Trunc(d); 
Writeln(i); 

这个程序输出62,而不是61。这是因为,虽然d*100以延长80位精度小于62,closest double precision value to that 80 bit value实际上是在62

同样,如果你与你的编译原始程序64位编译器,然后在没有80位寄存器的SSE单元中执行算术运算。所以没有80位的中间值和你的程序输出62.

或者,回到32位编译器,你可以安排在FPU上存储64位精度的中间值,也可以获得62.拨打Set8087CW($1232)即可实现。

正如您所看到的,二进制浮点运算有时可能会令人惊讶。


如果使用Round而不是Trunc则返回值将是最接近的整数,而不是向零取整为Trunc一样。

但也许更好的解决方案是使用十进制数据类型而不是二进制数据类型。如果你这样做,那么你可以准确地表示0.62,从而避免所有这些问题。德尔福内置的十进制实数值数据类型为Currency

+0

+1是否精确。 – 2014-09-02 15:18:19

4

使用round而不是trunc

round会向最接近的整数舍入,而62.00非常接近62,所以没有问题。 trunc将四舍五入到最接近的整数朝向零,并且62.00非常接近61.9999999,因此数字“模糊”可能会导致您描述的问题。

相关问题