一、四捨五入法
四捨五入是一種應用非常廣泛的近似計算方法,其有算術捨入法和銀行家捨入法兩種。
所謂算術捨入法,就是我們通常意義上的四捨五入法。其規則是:當捨去位的數值大於等於5時,在捨去該位的同時向前位進一;當捨去位的數值小於5時,則直接捨去該位。
所謂銀行家捨入法,其實質是一種四捨六入五留雙(又稱四捨六入五奇偶)法。其規則是:當捨去位的數值小於5時,直接捨去該位;當捨去位的數值大於等於6時,在捨去該位的同時向前位進一;當捨去位的數值等於5時,如果前位數值為奇,則在捨去該位的同時向前位進一,如果前位數值為偶,則直接捨去該位。
綜上所述,兩種捨入法所得結果不盡一致,因此在使用時必須根據實際需要加以區別。否則會出現一些莫明其妙的偏差。
二、delphi中的四捨五入函式
眾所周知,delphi中有乙個四捨五入取整函式round。但它是按銀行家捨入法的規則實施捨入操作的,delphi中沒有按算術捨入法規則實施捨入操作的四捨五入取整函式。
在delphi中使用四捨五入函式一直是使用round,可是有時候發現,使用它得到的答案與我們預期的會不太一樣。
舉例:i := round(11.5)結果: i=12
i := round(10.5)結果: i=10
是的,按照我們的預期,第二個函式應該返回11才對,可是,為什麼會這樣呢?
對於***.5的情況,整數部分是奇數,那麼會round up,偶數會round down。難道是delphi的bug?
no!! 讓我們看看<"在最近版本的delphi pascal 編譯器中,round 函式是以 cpu 的 fpu (浮點部件) 處理器為基礎的。這種處理器採用了所謂的 "銀行家捨入法",即對中間值 (如 5.5、6.5) 實施round函式時,處理器根據小數點前數字的奇、偶性來確定捨入與否,如 5.5 round 結果為 6,而 6.5 round 結果也為6, 因為 6 是偶數"。
round函式其實使用的銀行家演算法進行運算的,統計學上一般也是使用這種演算法的,這比我們傳統的四捨五入方法要科學,可是,如果我們要使用傳統的四捨五入的方法,該如何解決呢?
有人是這樣解決的,給10.5加上乙個很微小的數值,再呼叫round函式,這樣在不影響精度的同時,就得到了正確的結果,貌似不錯,可這始終是治標不治本的方法,有沒有更正統的解決方法呢?
在網上又搜到了乙個函式:
function doround(value: extended): int64;
procedure set8087cw(newcw: word);
asmmov default8087cw,ax
fnclex
fldcw default8087cw
end;
const
roundupcw = $1b32;
varoldcw : word;
begin
oldcw := default8087cw;
try
set8087cw(roundupcw);
result := round(value);
finally
set8087cw(oldcw);
end;
end;
先解釋一下8087cw, 全稱是8087 control word。它是cpu中浮點單元(fpu)控制器控制字的值,設定8087cw,會改變fpu的精度,捨入模式,以及運算出錯時是否產生異常。
上面程式的思路很簡單,就是先儲存8087cw,然後設定它為round up,這樣偶數時就不會round down了,最後再還原8087cw。
其實上面的函式還可以簡化,因為system單元裡已經提供了set8087cw的實現,所以程式簡化為
function doround(value: extended): int64;
const
roundupcw = $1b32;
varoldcw : word;
begin
oldcw := default8087cw;
tryset8087cw(roundupcw);
result := round(value);
finally
set8087cw(oldcw);
end;
end;
到這裡為止,這篇文章可以告一段落了,可是,經過摸索,我發現另一種相似而有趣的解決方案。
其實borland早就想到我們會遇到這樣的問題,想到我們需要定製fpu的捨入模式,所以它提供了現成的函式供我們使用。在math單元裡,有乙個setroundmode函式。下面是我封裝的乙個四捨五入函式:
function roundex(value: extended; roundmode: tfpuroundingmode = rmup): int64;
varrm: tfpuroundingmode;
begin
rm := getroundmode;
trysetroundmode(roundmode);
result := round(value);
finally
setroundmode(rm);
end;
end;
舉例:i := roundex(11.5)結果: i=12
i := roundex(10.5)結果: i=11
嗯,這樣對了吧,如果我設定成其它roundmode會怎樣呢?
舉例:i := roundex(11.5, rmtruncate)結果: i=11
i := roundex(10.5, rmtruncate)結果: i=10
roundex函式華麗的變身為trunc函式了,是不是很有趣啊,哈哈!
Delphi的四捨五入函式
小中 大一 四捨五入法 四捨五入是一種應用非常廣泛的近似計算方法,其有算術捨入法和銀行家捨入法兩種。所謂算術捨入法,就是我們通常意義上的四捨五入法。其規則是 當捨去位的數值大於等於5時,在捨去該位的同時向前位進一 當捨去位的數值小於5時,則直接捨去該位。所 謂銀行家捨入法,其實質是一種四捨六入五留雙...
Delphi中的四捨五入函式
一 四捨五入法 四捨五入是一種應用非常廣泛的近似計算方法,其有算術捨入法和銀行家捨入法兩種。所謂算術捨入法,就是我們通常意義上的四捨五入法。其規則是 當捨去位的數值大於等於 5時,在捨去該位的同時向前位進一 當捨去位的數值小於 5時,則直接捨去該位。所謂銀行家捨入法,其實質是一種四捨六入五留雙 又稱...
qt的四捨五入 Qt(C )四捨五入
qt現在是四捨六入五成雙,要想四捨五入得自己想辦法,實現如下 include include double c1 3.435 double c2 3.445 double c3 3.4351 double c4 3.4451 double c5 3.445 qdebug qdebug qdebug ...