DELPHI四捨五入問題解決

沧江魅影發表於2024-08-15

轉自http://www.delphitop.com/html/jichu/153.html 感謝原作者。

這段時間在用DELPHI做一個財務系統時發現每一行的小計取了兩位小數後與用SQL的ROUND查詢出來的不一樣,在程式中是用FormatFloat('0.00',ItemSum)函式來取值的,再用DXDBGRID網格顯視合計,最終與SELECT SUM(ROUND(ITEMSUM,2))得出的結果是不一樣的。

例如ItemSum:=1.005,在程式FormatFloat('0.00',ItemSum)就返回是“1”,應該是“1.01”才是。

因為以前做的系統都沒有用DXDBGIRD來顯視合計, 一直都沒留意這個問題,然後新建了一個程式來測試,用FormatFloat('0.00',1.005)得出是“1.01”是正確的,這是怎麼回事呢,將1.005付給變數ItemSum再FormatFloat('0.00',ItemSum)就返回是“1”,單步除錯時ItemSum一直都是1.005,透過變數同一個資料就有不同的結果。

一開始ItemSum是Double型別的,後來改為Extended後FormatFloat('0.00',ItemSum)就返回是“1.01”了,為什麼會這樣呢,後來想了一下可能是Double型別,因為在計算機中數是用二進位制儲存的,而十進位制的有限小數轉換成二進位制可能變成無限小數,所以儲存的時候會有一定的誤差。在通常情況下,如果要比較兩個數的大小,必須透過對它們的求差得到,如比較ItemSum1與ItemSum是否相等,應用abs(ItemSum1-ItemSum1)<0來判斷。1.005就變成了1.004999999999999....了。

使用Extended或者FormatFloat('0.00',StrToFloat(FlotToStr(ItemSum)))就解決問題了。

**************************

在DELPHI中Round()和RoundTo()都是四捨五入的函式,但DELPHI用的四捨五入與一般的四捨五入不同,它採用的是四捨六入五留雙。

即當舍或入位大於或小於五時按四捨五入來處理,而當舍或入位等於五時,就要看前面一位是什麼,根據奇進偶不進,它總是返回一個偶數值。

這種演算法其實是按照銀行家演算法,統計學上一般都用這種演算法,比傳統的"四捨五入"要科學。在VB、.net相關的語言中都有這個問題。

例如:

表示式 返回值

Round(11.5) 12

Round(10.5) 10

RoundTo(1234567, 3) 1234000

RoundTo(1.234, -2) 1.23

RoundTo(1.235, -2) 1.24

RoundTo(1.245, -2) 1.24

如果要使用傳統的"四捨五入"方法,可以使用下面函式:

function RoundEx(R: Real): Int64;

begin

Result:= Trunc(R);

if Frac(R) >= 0.5 then

Result:= Result + 1;

end;

function DRound(const Value: Extended; const Digit: Byte = 0): Extended;

var

tmp: Extended;

begin

tmp := Power(10, Digit);

if Value > 0 then

Result := Value * tmp + 0.5

else

Result := Value * tmp - 0.5;

Result := Trunc(Result) / tmp;

end;

相關文章