2013-02-22 217 views
1

我有以下代碼圓貨幣四捨五入貨幣

function MyRound(value :currency) : integer; 

begin 
    if value > 0 then 
    result := Trunc(value + 0.5) 
    else 
    result := Trunc(value - 0.5); 
end; 

它運作良好,到目前爲止,我現在的問題是,如果我想圓一個貨幣一樣999999989000.40因爲特呂克它給負值需要int並且MyRound也返回int。

我可能的解決方案是將貨幣轉換爲字符串並獲得之前的字符串。並將字符串轉換回貨幣。這是一個正確的方法嗎?我對delpi很陌生,所以請幫助我。

+2

使用int64而不是整數? – 2013-02-22 12:25:16

+1

您建議的解決方案是錯誤的,並且不會工作,因爲您的問題是32位溢出 – kludg 2013-02-22 12:41:20

回答

4

你過於複雜的事情。你可以簡單地使用Round

program Project1; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    C: Currency; 

begin 
    C := 999999989000.4; 
    Writeln(Round(C)); 
    C := 999999989000.5; 
    Writeln(Round(C)); 
    C := 999999989000.6; 
    Writeln(Round(C)); 
    C := 999999989001.4; 
    Writeln(Round(C)); 
    C := 999999989001.5; 
    Writeln(Round(C)); 
    C := 999999989001.6; 
    Writeln(Round(C)); 
    Readln; 
end. 

其輸出

 
999999989000 
999999989000 
999999989001 
999999989001 
999999989002 
999999989002 

如果你不想銀行家舍,和你真的想你Trunc邏輯,那麼你就需要編寫自己的函數。但是你的函數的問題是它被截斷爲32位整數。使函數返回一個64位整數:

program Project1; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils, Math; 

var 
    C: Currency; 

function MyRound(const Value: Currency): Int64; 
begin 
    if Value > 0 then 
    result := Trunc(Value + 0.5) 
    else 
    result := Trunc(Value - 0.5); 
end; 

begin 
    C := 999999989000.4; 
    Writeln(MyRound(C)); 
    C := 999999989000.5; 
    Writeln(MyRound(C)); 
    C := 999999989000.6; 
    Writeln(MyRound(C)); 
    C := 999999989001.4; 
    Writeln(MyRound(C)); 
    C := 999999989001.5; 
    Writeln(MyRound(C)); 
    C := 999999989001.6; 
    Writeln(MyRound(C)); 
    Readln; 
end. 
 
999999989000 
999999989001 
999999989001 
999999989001 
999999989002 
999999989002 
+4

Doesn在2.5到2和3.5到4之間(或者相反,永遠不會記住),那麼這個輪子就會遭受銀行家的四捨五入:0.5技巧是解決FPU設置的最簡單方法嗎? – 2013-02-22 12:31:34

+2

@ MarjanVenema嗯,這就是'Round'的工作方式,如果你想要一些不同的東西,那麼使用不同的東西。 – 2013-02-22 12:36:27

+6

那麼,給定標準的FPU設置,這是多麼圓潤的工作。提供基本的數學知識,但沒有財務背景,並不是人們如何期待圓滿工作。當我發現它時,它肯定讓我感到驚訝...... – 2013-02-22 12:43:44

6

從我的角度來看,你有兩個選擇:

  1. 您使用Round功能,如大衛·赫弗南指出;
  2. 您可以使用SimpleRoundTo函數,如here所述。 SimpleRoundTo的優點是它可以接收參數Single,DoubleExtended數據類型,並且它們可以很好地轉換數據類型,如上所述。

您不需要任何類型轉換。有很多舍入功能可供您使用。圍繞期望的數字。

+1

SimpleRoundTo(...,0)與Round(...)有什麼不同? – 2013-02-22 15:14:03

+0

@DavidHeffernan在這種情況下,它沒有。這就是爲什麼我說你的解決方案給出了相同的結果。但是,如果要將數字舍入到給定的精度,它會有所不同。 'Round(...)'是SimpleRoundTo(...,0)的一個特例' – 2013-02-22 15:31:16

+1

@DavidHeffernan:它不使用銀行家的四捨五入。根據Bogdan鏈接到的文檔:「此函數的結果取決於當前的FPU舍入模式...要在」銀行家模式「中舍入,請使用System.Math.RoundTo。」 – 2013-02-22 15:31:57

0

這是我實際使用(很想聽聽是否有使用這種方法的任何問題!):

function RoundingFunction(X: Real): Int64; 
begin 
    Result := Trunc(SimpleRoundTo(X, 0)); 
end; 
+0

'SimpleRoundTo(x,0)'不留下小數,恕我直言,'Trunc'函數在那裏沒用。 – 2013-02-22 15:32:44

+0

編譯器不同意 – 2013-02-22 15:33:05

+0

它不同意什麼? – 2013-02-22 15:34:14

0

看看約翰Herbster的舍入例程。他們提供了將近您可能希望任何類型的舍入,例如:

drNone, {No rounding.} 
drHalfEven,{Round to nearest or to even whole number. (a.k.a Bankers) } 
drHalfPos, {Round to nearest or toward positive.} 
drHalfNeg, {Round to nearest or toward negative.} 
drHalfDown,{Round to nearest or toward zero.} 
drHalfUp, {Round to nearest or away from zero.} 
drRndNeg, {Round toward negative.     (a.k.a. Floor) } 
drRndPos, {Round toward positive.     (a.k.a. Ceil) } 
drRndDown, {Round toward zero.      (a.k.a. Trunc) } 
drRndUp); {Round away from zero.} 

我不能給你一個鏈接的權利,但谷歌:小數四捨五入約翰Herbster 我覺得他最近的舍入例程在DecimalRounding_JH1.pas 。他對浮點舍入的討論(在英巴卡迪諾的網站上的某處是一個「必讀」。