2014-09-02 36 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,因此數字「模糊」可能會導致您描述的問題。

相關問題