2011-11-08 41 views
8

我的應用程序是用Delphi5編寫的。我正在使用madExcept來追蹤錯誤。我跟蹤了一個「零點浮動點」異常,它不應該在那裏。代碼段的位置如下所示:Delphi5中的零異常的浮點除法

val:=100*Power(1.25,c); 

其中'c'實際上始終具有值'1'。

日誌的堆棧跟蹤:

main thread ($338f8): 
00403504 +010 MyApp.exe System 1970 +5 @FRAC 
00479148 +058 MyApp.exe Math    Power 
007ae8a6 +262 MyApp.exe MyClass 1962 +36 TMyClass.FormMouseWheel 

我有另一個異常在一個點上,其中一個部門確實發生,但是除數是一個變量,它的值也爲「1」時,異常發生。我能夠調試和複製。

我的問題:我錯過了什麼?有沒有我不知道的浮點除法的一些誤報?另外:我在異常點不使用任何C++ DLL,因爲它們傾向於以不同的方式處理FP分區(返回NaN或+/- INF而不是引發異常)。

任何指針讚賞。

+3

聽起來不太合理。我認爲你的調試工具並沒有把你指向正確的地方,或者變量不能保持你的想法。 –

+0

不記得D5是否已經擁有它,但是當你執行代碼時,你是否嘗試檢查CPU/FPU視圖中發生了什麼? – 2011-11-08 09:04:31

+0

@ldsandon當然D5已經允許使用Alt-F2並進入CPU/FPU視圖。好主意。但是我猜想一個未處理的FPU異常會在'System._Frac'代碼中破壞。 –

回答

8

我只是想下面的代碼:

procedure TTTest.FormCreate(Sender: TObject); 
var v: extended; 
    one: extended; 
begin 
    one := 1.0; 
    v := 100*Power(1.25,one); 
end; 

它只是編譯和運行按預期在Delphi 5

我的猜測是,每零標誌的劃分可能是你的代碼之外設置(甚至如果你沒有鏈接到C++代碼,調用Direct X或者可能會有相同的效果),但是稍後在_Frac中提出。

標準實施Power()中唯一致電Frac的是測試Frac(Exponent) = 0.0

有在Frac的Delphi 5和Delphi 6之間執行一個修改

這裏是Delphi 5的版本:

procedure  _FRAC; 
asm 
    FLD  ST(0) 
    SUB  ESP,4 
    FSTCW [ESP] 
    FWAIT 
    FLDCW cwChop 
    FRNDINT 
    FWAIT 
    FLDCW [ESP] 
    ADD  ESP,4 
    FSUB 
end; 

這裏是Delphi 6的版本:

procedure  _FRAC; 
asm 
    FLD  ST(0) 
    SUB  ESP,4 
    FNSTCW [ESP].Word  // save 
    FNSTCW [ESP+2].Word // scratch 
    FWAIT 
    OR  [ESP+2].Word, $0F00 // trunc toward zero, full precision 
    FLDCW [ESP+2].Word 
    FRNDINT 
    FWAIT 
    FLDCW [ESP].Word 
    ADD  ESP,4 
    FSUB 
end; 

從上面的代碼中,你會發現以下命令導致在Delphi 6發佈之前引發延遲異常:Trunc,Frac,Ceil 。

所以我想你遇到了Delphi 5的問題,Delphi 5已經修復了這個問題。您可能需要使用自己的動力版本,像這樣的:

function Power(Base, Exponent: Extended): Extended; 
begin 
    if Exponent = 0.0 then 
    Result := 1.0    { n**0 = 1 } 
    else if (Base = 0.0) and (Exponent > 0.0) then 
    Result := 0.0    { 0**n = 0, n > 0 } 
    else 
    Result := Exp(Exponent * Ln(Base)) 
end; 
+0

爲我解決問題的好答案。小挑揀,但答案可以通過解釋每個裝配線正在做什麼的註釋來改進 - 至少對於關鍵線來說。或者,總結一下每個_FRAC過程的作用(在堆棧上推舊的CW,設置新的CW,執行操作,從堆棧中彈出舊的CW,諸如此類的東西)。對那些不熟悉x86彙編的我們來說會有幫助。 :) –

2

不以任何方式一個明確的答案,但是......

FPU相關的例外情況,不應該有,可能與沒有正確清除FPU堆棧。儘管我們遇到了無效的浮點操作異常,但我們在一個階段遇到了類似的問題。

這篇文章:Delphi bug of the day: FPU stack leak有人跟蹤由S := S + '*';拋出的無效浮點操作異常的原因,幫助我們解決了這個問題。