2011-11-08 60 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」のとき、例外が発生しました。私はそれをデバッグして再現できました。

私の質問:何が欠けていますか?私が気づいていない浮動小数点除算について、誤った評価がいくつかありますか?

さらに例外を発生させるのではなく、NaNまたは+/- INFを返すようにFP分割を処理する傾向があるため、例外ポイントでC++ DLLを使用していません。

+3

非常にそうではありません。私はあなたのデバッグツールがあなたを正しい場所に向けるとは思っていません。あるいは、変数があなたの考えを保持していないかもしれません。 –

+0

D5に既にそれがあったのを覚えていないが、そのコードが実行されたときにCPU/FPUビューで何が起きているのかチェックしようとしましたか? –

+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; 

をデルファイ5.

に予想通りそれはちょうど私の推測では、ゼロフラグあたり部門は、コード外に設定することができるということであるコンパイルし、実行します(偶数C++コードにリンクしていない場合、Direct Xなどを呼び出すと同じ効果が得られる可能性がありますが、後で呼び出されるのは_Fracです)。

Power()の標準実装でFracへの唯一の呼び出しがFrac(Exponent) = 0.0をテストすることです。

ここ

デルファイ5バージョンであるデルファイ5とDelphi 6の間Fracの実装における変形

あった:

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; 
:ここ

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バージョンであります

上記のコードから、Delphi 6がリリースされる前に遅延例外が発生したことがわかります:Trunc、Frac、Ceil 。

だから、Delphi 6で修正された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 leakS := S + '*';によって無効な浮動小数点演算例外がスローされた理由を誰かが追跡したところ、この問題を解決するのに役立ちました。

0

あなたはEmbeddedWBようTWebBrowserまたは任意のIEのウェブブラウザコンポーネントを使用していますか?

もしそうなら、これはそれを説明するかもしれない: https://forums.embarcadero.com/thread.jspa?messageID=334125&tstart=0

それはまた、あなたが上記の説明のJeroenによって提供されたリンクとしてウェブブラウザ(Set8087CW)を使用していない場合でも、問題を解決するかもしれない何かが含まれています。