小さな単純な浮動小数点演算から時折奇妙な結果が得られるソフトウェア プロジェクトがあります。私が見逃しているものがあると思います。次の問題をデバッグする方法についてのヒントが欲しいです。
(使用されるコンパイラは、Microsoft C コンパイラのバージョン 12 である MS VC 6.0 です)
最初の異常:
extern double Time, TimeStamp, TimeStep; // History terms, updated elsewhere
void timer_evaluation_function( ) {
if ( ( Time - TimeStamp ) >= TimeStep ) {
TimeStamp += TimeStep;
timer_controlled_code( );
}
{....}
何らかの理由で、タイマーの評価が失敗し、時間指定されたコードが実行されませんでした。デバッガーでは、トリガー条件が実際に真であることを確認するのに問題はありませんでしたが、FPU は肯定的な結果を見つけることを拒否しました。次のコード セグメントは、同じ操作を実行しましたが、問題はありませんでした。この問題は、失敗する可能性のある偽の評価を挿入することで回避されました。
FPU の状態は、実行された以前の操作によって何らかの形で汚染されていると思いますが、役立つコンパイラ フラグがいくつかあるのでしょうか?
2番目の異常:
double K, Kp = 1.0, Ti = 0.02;
void timed_code( ){
K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 )
{....}
デバッガーは式を約 0.05 と評価しますが、結果は #IND です。#IND 値は、fld 命令を使用して 2.0F 値が FPU にロードされると、FPU スタックに表示されます。前の命令は、fild 命令を使用して、整数値 2000 を double float としてロードします。FPU スタックに #IND 値が含まれると、すべてが失われますが、デバッガーは数式を問題なく評価します。後で、これらの操作は期待される結果を返します。
また、関数呼び出しの直後に FPU の問題が再び発生します。各新しい関数の後に FPU 状態をクリアする浮動小数点演算を挿入する必要がありますか? 何らかの方法で FPU に影響を与える可能性のあるコンパイラ フラグはありますか?
この時点で、すべてのヒントとコツに感謝します。
編集:トップ関数でアセンブリ関数EMMSを最初に呼び出すことで、問題を回避できました。そうすれば、私のコードが呼び出された環境で作成された、または作成されなかった可能性のある MMX 関連のガベージが FPU からクリアされます。FPU の状態は当然のことではないようです。
//フランク