bestlong 怕失憶論壇's Archiver

bestlong 發表於 2007-3-7 10:49

Round 函數不正確的四捨五入狀況

[code]Delphi 的 Round() 四捨五入函數採奇入偶捨方式, Ex:

  Round(1.5) => 2
  Round(2.5) => 2
  Round(3.5) => 4

2.5 得到的結果怎麼會是 2 呢?

解決之道: 自己寫四捨五入函數, 以下提供兩種:

  方法一:

    function MyRound(P: Double; Decimals: integer): Double;
    var
      factor: LongInt;
      help: Double;
      i: integer;
    begin
      factor := 1;
      for i := 1 to decimals do
        factor := factor * 10;
  
      if P < 0 then
        help := -0.5
      else
        help := 0.5;
      Result := Int(P*factor+help) / factor;
      if (Result > -0.00000001) and (Result < 0.00000001) then
        Result := 0.00;
    end;

  方法二: 利用 FloatToStrF 及 StrToFloat 函數:
   
    function MyRound(P: Double; Decimals: integer): Double;
    var
      s: string;
    begin
      s := FloatToStrF(P, ffFixed, 15, Decimals)
      Result := StrToFloat(s);
    end;[/code]

bestlong 發表於 2007-4-4 15:22

在Delphi中使用Round函數得到的答案有時與我們所預期的會不太一樣:

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

     範例             結果
i:= Round(11.5)        12
i:= Round(10.5)        10

這種Round其實是按照銀行家演算法,統計學上一般都用這種算法,比傳統的"四捨五入"要科學。
如果要使用傳統的"四捨五入"方法,可以使用下面函數:[code]function RoundClassic(R: Real): Int64;
begin
  Result:= Trunc(R);
  if Frac(R) >= 0.5 then
    Result := Result + 1;
end;[/code]其實在VB、Excel、.NET相關的語言中都有這個問題。

bestlong 發表於 2009-12-17 09:16

從 Delphi 6 開始可以使用 SimpleRoundTo() 函數來處理四捨五入,而 Delphi 5 環境就需要自己補上,不過可以參考 D6 或 D7 的程式碼。

bestlong 發表於 2010-5-26 20:56

四捨五入喔,不要再忘記了~

From [url]http://jasper-dale.spaces.live.com/blog/cns!6C55F63E92E2726C!470.entry[/url]

每次要用到 四捨五入 都忘記是那個指令!

function Round(X: Extended): Int64;

If X is exactly halfway between two whole numbers, the result is always the even number.
如果X剛好在兩數的中間,那回傳的數將會是 "偶數" 的那一個。
This method of rounding is often called "Banker's Rounding".
我才不管什麼 "Banker's Rounding" ,實用最重要。
在網路上找到很多資訊,加以小改一下成為台灣適用的『四捨五入』
就呼叫自己的 RoundF 吧![code]function RoundF(X: Extended; Decimal: integer = 0): Extended;
var
  PowerNum: Extended;
begin
  PowerNum := IntPower(10, Decimal);
  Result := RoundI(X * PowerNum) / PowerNum;
end;

function RoundI(X: Extended): Int64;
begin
  if X < 0 then
    Result := Round(X - 0.0000001)
  else
    Result := Round(X + 0.0000001);
end;[/code]

bestlong 發表於 2011-3-8 11:49

參考樓上的修改成這樣[code]
function RoundF(X: Extended; Decimal: integer = 2): Extended;
var
  PowerNum: Extended;
begin
  PowerNum := IntPower(10, Decimal);
  if X < 0 then
    Result := Round((X * PowerNum) - 0.1) / PowerNum
  else
    Result := Round((X * PowerNum) + 0.1) / PowerNum;
end;
[/code]測試程式[code]unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Math;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function RoundF(X: Extended; Decimal: integer = 2): Extended;
var
  PowerNum: Extended;
begin
  PowerNum := IntPower(10, Decimal);
  if X < 0 then
    Result := Round((X * PowerNum) - 0.1) / PowerNum
  else
    Result := Round((X * PowerNum) + 0.1) / PowerNum;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  f: Double;
begin
  Memo1.Clear;
  f := 1213.245;
  Memo1.Lines.Append(floattostr(f));
  Memo1.Lines.Append(FloatToStr(RoundF(1213.245, 2)));
  Memo1.Lines.Append(FloatToStr(RoundF(f, 2)));
  Memo1.Lines.Append('');
  f := -1213.245;
  Memo1.Lines.Append(floattostr(f));
  Memo1.Lines.Append(FloatToStr(RoundF(-1213.245, 2)));
  Memo1.Lines.Append(FloatToStr(RoundF(f, 2)));
end;

end.
[/code]執行結果
頁: [1] 2

Powered by Discuz! X1.5 Archiver   © 2001-2010 Comsenz Inc.