一、四捨五入法
四捨五入是一種應用非常廣泛的近似計算方法,其有算術捨入法和銀行家捨入法兩種。
所謂算術捨入法,就是我們通常意義上的四捨五入法。其規則是:當捨去位的數值大於等於
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 ...