2012-08-13 30 views
6

在Delphi6或Delphi 2010中,聲明Currency(vtemp1,vtemp2)類型的兩個變量併爲它們提供0.09的值。 用ABS函數嵌入其中一個變量並將其與另一個進行比較。 由於編譯器 監視器顯示abs(vtemp1)和vtemp2的值相同,因此可以預期該比較會產生積極結果。 奇怪的是,如果聲明失敗!ABS函數在Delphi中失敗

注: - 這與 數0.09打交道時,問題只有經歷(嘗試其他幾個接近值顯示正常結果) -Declaring爲Double而不是貨幣,這個問題不再存在變量。

+2

無法重現 – kludg 2012-08-13 07:12:37

+3

[比較浮點值有多危險?](http://stackoverflow.com/questions/10334688/how-dangerous-is-it-to-compare-floatingpoint -values) – valex 2012-08-13 07:47:50

+0

使用'數學'或類似的'SameValue'。 – 2012-08-13 07:55:53

回答

16

我認爲原因是類型轉換。 Abs()函數返回real結果,所以currency變量轉換爲real。看看文檔:

貨幣是一種定點數據類型,可以最大限度地減少貨幣計算中的舍入錯誤。在Win32平臺上,它被存儲爲縮放的 64位整數,最後四位有效數字隱含地代表小數位數 。當在 分配和表達與其他真實類型混合,貨幣值被自動分割 或乘以10000

所以貨幣是固定的,並且是真正的浮點。你的問題 示例代碼:

program Project3; 
{$APPTYPE CONSOLE} 

const VALUE = 0.09; 
var a,b : currency; 
begin 
    a := VALUE; 
    b := VALUE; 

    if a = Abs(b) then writeln('equal') 
    else writeln('not equal', a - Abs(b)); 

    readln; 
end. 

產生,因爲類型轉換的不等於結果;

編譯腕錶揭示了ABS(vtemp1)和vtemp2

嘗試同樣的值加x : real,然後調用x := abs(b);,加x到手錶列表,選擇它並按Edit watch,然後選擇浮點。 X變成0.899...967

不僅0.09值產生這樣的結果。你可以試試這個代碼來檢查:

for i := 0 to 10000 do begin 
     a := a + 0.001; 
     b := a; 
     if a <> abs(b) then writeln('not equal', a); 
    end; 

所以,如果你需要貨幣變量的絕對值 - 就這樣做。不要使用浮點數abs()

function Abs(x : Currency):Currency; inline; 
    begin 
     if x > 0 then result := x 
     else result := -x; 
    end; 
+0

感謝您的提示答覆,正如您所指出的,我使用了類似的解決方法來避免此問題。儘管解釋是有道理的,但是這不是Delphi IDE或編譯器本身的錯誤嗎? – Johny 2012-08-13 08:56:07

+2

@Khatchig - 從形式上說,這不是一個錯誤,而是一個記錄的行爲(「按設計」)。我同意這是一個不好的行爲,Embarcadero可以修復它(使'Abs(貨幣)'返回一種貨幣類型,而不是浮動貨幣)。 – kludg 2012-08-13 12:14:14

6

稍加說明。如果浮點值進行比較的「問題」出現:

var 
    A: Currency; 

begin 
    A:= 0.09; 
    Assert(A = Abs(A)); 
end; 

這是因爲Abs(A)返回一個浮點值,A = Abs(A)作爲一個float實現比較。

我不能重現它,如果貨幣值進行比較:

var 
    A, B: Currency; 
begin 
    A:= 0.09; 
    B:= Abs(A); 
    Assert(A = B); 
end; 

但第二樣品也是一個潛在的錯誤的原因B:= Abs(A)內部是由10000浮法分割/乘法與舍入到貨幣(int64類型),並依賴於FPU舍入模式。


我創建了一個qc report #107893,它被打開了。

1

我剛剛發現了困難的方式,德爾福XE2 Abs功能不超載的貨幣類型。

Delphi XE2 docwiki

這些都是由ABS

  • 功能阿布斯支持(X:):只有真正的類型;超載;
  • 函數Abs(X:):Int64;超載;
  • 函數Abs(X:):Integer;超載;