2015-11-17 166 views
-1

在我的Delphi XE2項目中,我使用一些實際變量來計算一些憑證相關數據。我寫了下面的代碼:Delphi中的浮點數小數點近似值

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math; 

type 
    TForm1 = class(TForm) 
    Edit1: TEdit; 
    Edit2: TEdit; 
    Edit3: TEdit; 
    Edit4: TEdit; 
    Edit5: TEdit; 
    Edit6: TEdit; 
    Label1: TLabel; 
    Label2: TLabel; 
    Label3: TLabel; 
    Label4: TLabel; 
    Label5: TLabel; 
    Label6: TLabel; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    ServiceTax, RetailPrice, ProcessingFee, VoucherValue, AccountBalance, Airtimepercentage : real; 
begin 
    RetailPrice := StrToFloatDef(Edit1.text, 0); 
    ServiceTax := StrToFloatDef(Edit2.text, 0); 
    if (RetailPrice*(10/100) <= 5) then ProcessingFee := RetailPrice*(10/100) else ProcessingFee := 5; 
    VoucherValue := (RetailPrice/(1+(ServiceTax/100)) - ProcessingFee); 
    AccountBalance := StrToFloatDef(Edit5.text, 0); 
    AirTimePercentage := (AccountBalance/VoucherValue)*100; 
    Edit3.Text := FloatToStrF(ProcessingFee, ffFixed, 16, 6); 
    Edit4.Text := FloatToStrF(VoucherValue, ffFixed, 16, 6); 
    Edit6.Text := FloatToStrF(AirTimePercentage, ffFixed, 16, 6); 
end; 

end. 

但問題是,VoucherValue是一個浮點數。它包含一個非常長的小數點,但我的要求最多隻有兩個小數點,或者可能是一個長整數小數點,但小數點後兩位(示例12.19)所有數字都將爲零(例如12.190000)。所以,我試圖FormatFloat如下:

VoucherValue := StrToFloatDef(FormatFloat('0.##', FloatToStrF((RetailPrice/(1+(ServiceTax/100)) - ProcessingFee), ffFixed, 16, 6)), 0); 

但我無法編譯,得到錯誤如下:

[dcc32 Error] Unit1.pas(46): E2250 There is no overloaded version of 'FormatFloat' that can be called with these arguments

FormatFloat另一個缺點是,它可以截斷(即12.129999到12.12)但不能近似(即12.129999到12.13),但我需要近似值。

另一種解決方案是使用另一個字符串變量,但我不喜歡使用。

請給我建議。

+1

另一天,誰需要另一個人閱讀本:WECSSKAFP(戈德堡,1991) https://docs.oracle.com/cd/E19957 -01/806-3568/ncg_goldberg.html –

+0

你不能使用浮點類型來賺錢。改用貨幣。 – Johan

回答

2

我懷疑真正的問題是您的價值無法代表,這是一個多次討論的問題。您的值不能用二進制浮點完全表示。

你有兩個主要選擇:

  • 離開類型和值是,但格式輸出小數點後兩位。例如Format('%.2f', [Value])FormatFloat('0.##', Value)。與你在問題中所說的相反,FormatFloat確實到了最近。
  • 使用十進制數據類型,因此可以精確地表示值。
4

當編譯器告訴你沒有超載接受你給出的參數時,你應該做的第一件事就是檢查哪些超載是可用的。然後你會看到所有的FormatFloat過載期望第二個參數的類型爲Extended。你傳遞的結果是FloatToStrF,它返回一個字符串。 (此外,當您撥打FloatToStrF時,您要求小數點後六位,因此您不會得到一個舍入到兩位的值。)

請勿在格式化之前將值轉換爲字符串它;這就是FormatFloat已經做到的。

VoucherValue := StrToFloatDef(FormatFloat('0.##', (RetailPrice/(1+(ServiceTax/100)) - ProcessingFee)), 0); 

更好的是,不要將您的值轉換爲字符串,如果一個字符串實際上不是你想要的。您顯然仍然想要一個數字值四捨五入到一定的數量,所以請撥打RoundTo就可以了。對於兩位小數,第二個參數應該是− 2.

VoucherValue := RoundTo(RetailPrice/(1+(ServiceTax/100)) - ProcessingFee, -2); 
+0

更好的是,寫一些更簡單的子表達式,而不是看看你可以塞進一行。 –

+0

我認爲值得指出的是,RoundTo將舍入到最接近的可表示值 –