6

私の本質的な問題は、クラシック MacOS (CodeWarrior) から Windows (VS 2008) に移行して、x86 で浮動小数点演算を PowerPC のように動作させる方法です。

問題のコードには、非常に反復的で数値的に非常に敏感なアルゴリズムが山積みされています。

典型的な複雑な行は次のとおりです。

Ims_sd = sqrt((4.0*Ams*sqr(nz)-8.0*(Ams+Dms)*nz+12.0*sqr(Ams)) /
         (4.0*sqr(Ams)*(sqr(nz)-1)) - 
         sqr(Ims_av))*sqrt(nz-1);

float基本型としてtypedef を使用して記述されます。

に変更するdoubleと、両方のプラットフォームで非常に似た結果が得られますが、残念ながら数値が受け入れられないため、簡単に解決することはできません。

Mac コードは CodeWarrior を使用してコンパイルされており、FMADD および FMSUB 命令の生成をオフにするだけで、作成される数値に劇的な影響がありました。したがって、私の出発点は、最も類似していると思われる Visual Studio (2008) オプションを検索することでした - 融合追加が使用されていることを確認しました。その鍵は、計算で中間ストレージを割り当てる際のコンパイラの動作にあると思われます

現在、SSE2 と を有効にする組み合わせで最良の結果が得られてい/fp:fastます。組み込み関数を有効にすると、値が Mac の値からさらにずれます。

/fpスイッチのドキュメントには/fp:strict、融合された追加動作のみがオフになると記載されています。

MSDNでは、FP10.OBJ を「LIBC.LIB、LIBCMT.LIB、または MSVCRT.LIB の前に」リンクすることについて説明しています。64 ビットの精度を保証します。リンカの入力フィールドに FP10.OBJ を指定することで、これを達成したようです (詳細なリンカの出力は、MSVCRTD.lib の前にそれを示しています)。

また、呼び出して64ビット精度を設定しました

_controlfp_s(&control_word, _PC_64, MCW_PC);

DllMain で。

この問題は、プラットフォーム間の浮動小数点例外処理の違いによるものでも、PowerPC がゼロ整数による除算 (ゼロを返すだけ) を許可する (楽しい) 方法によるものでもないことに注意してください。 PCリント。プログラムが実行され、ある程度妥当な出力が生成されますが、十分ではありません。

アップデート:

友人からの興味深いコメント: 1 つの可能性として、PPC には 64 ビットの中間値を格納できる一時レジスタが多数あるのに対し、x86 コードでは FPU のアンロードと再ロードが必要になる場合があります (4 バイトに切り捨てられ、精度が失われます)。

これが、(IIRC)より多くのレジスタと中間値を保持するためのより多くの範囲があるため、SSE2がよりうまく機能する理由かもしれません。

1 つの可能性 - コードを 64 ビットとしてコンパイルできますか? x64 モードには、中間体用のレジスタが多く、FP 命令が優れているため、設計と実行において PPC に近い可能性があります。

彼が示唆したように、64 ビット ビルドでの最初のテストは、実際にはもっと近くなりました (最初はやり過ぎだと思っていましたが、それは不適切なモデリング設定が原因でした)。

最終決議

このトピックに興味を持っている人は、最終的にどのようにすべてがうまくいったかを知りたいと思うほど強迫観念を持っていると確信しています. ソフトウェアが完成し、一貫した数値結果が得られます。すべてのアルゴリズムで Mac に同じ結果を提供することはできませんでしたが、統計的に許容できるほど十分に近いものでした。専門家のユーザーが関心のある領域を選択することによって処理が導かれ、ユーザーの入力がモデルの進行状況に部分的に反応することを考えると、主任科学者はそれが受け入れられると判断しました (これは一晩で決定されたわけではありません!)。残りの数値の違いは、さまざまな臨床結果を決定するものの範囲内にあるため、テストではさまざまな診断が見られません.

4

3 に答える 3

3

複数のプラットフォームにまたがる浮動小数点決定論の問題全体は、非常に厄介な問題のようであり、掘り下げれば掘り下げるほど、問題は悪化するようです。

この問題について非常に詳細に議論している興味深い記事を見つけました - いくつかのアイデアを投げ出すことができるかもしれません.

于 2010-02-28T14:31:14.190 に答える
1

そのような答えではありませんが、コメントに収まるよりも多くのテキスト (および書式設定) があります。あなたの質問を読むと、あなたはおそらくこれらすべてを考慮しているように思えますが、私たちには話していないので、これはすべて無関係なおしゃべりかもしれません. もしそうなら、私は謝罪します。

プログラムの元のバージョンまたは移植されたバージョンのいずれかで、浮動小数点演算の IEEE754 規則への準拠を強制できますか (できましたか?)。私の最初の推測は、2 つのプラットフォーム (ハードウェア、o/s、ライブラリの組み合わせ) が fp 演算に対して異なるアプローチを実装していることです。

2 つのプラットフォームで、int や float などのいくつかの基本的な型のデフォルト サイズについて、どのような想定をしたか (ある場合)。C 標準 (および私は C++ 標準を信じています) は、そのようないくつかのプラットフォーム依存性を許可します (頭のてっぺんから覚えることはできません。私は実際には Fortran プログラマーです)。

最終的な推測 -- 私は (私の Fortranny の世界では) 4.0 のような float 定数を指定することに慣れてきました.4.0000000000000000000000. Fortran では、3.14159625 のような 4 バイトの float 定数が自動的に 8 バイトにキャストされると、余分なバイトが pi の 10 進数表現のそれ以上の桁数で埋められないことがわかっています。これはあなたに影響を与えている可能性があります。

これは、コードの移植されたバージョンが元のバージョンと同じ結果を生成することを保証するのに実際には役立ちません。違いの原因を特定するだけです。

最後に、新しいバージョンが古いバージョンと同じ結果を生成すること、または新しいバージョンが正確な回答を生成することを顧客に保証することが要件ですか? あなたの質問は、数値計算におけるエラーのすべての原因を考慮して、プログラムの古いバージョンが新しいバージョンよりも「間違っていた」可能性を残しています。

于 2010-01-28T09:31:34.360 に答える
1

GCC バグ 323を参照してください。

gcc のすべての x87 浮動小数点エラーが消滅するバグ 323 コミュニティの最新メンバーを歓迎したいと思います。x87 を使用するすべての浮動小数点エラーは歓迎されますが、それらの多くは簡単に修正できますが、多くはそうではありません! 私たちは皆、市場で最も正確な汎用 FPU から精度を求めるという重大な過ちを犯しており、1 つの幸せな家族です。

簡単にまとめると、x87 で「真の」IEEE 浮動小数点シングル/ダブルを取得するのは非常に面倒であり、パフォーマンスが大幅に低下することはありません。指数範囲が縮小されているために使用しても、デノルムの二重丸めに悩まされfldcwます(IIRC、IEEE FPは、実装が独自のWRTデノルムを実行できるようにします)。おそらく、次のようなことができます。

  1. 正の無限大に丸め、演算を実行し (ldresult1 を取得)、最も近い偶数に丸め、float に変換します (fresult1 を取得)。
  2. RTNI、演算を実行、RTNE、float に変換。
  3. それらが同じである場合、すばらしい: 正しい RTNE float の結果が得られました。そうでない場合、(私が思うに) fresult2 < fresult1 であり、さらに fresult1=nextafterf(fresult2,+inf) であり、次の 2 つの可能性があります。
    • ldresult1 == ((long double)fresult1+fresult2)/2. 「正しい」答えは fresult2 です。
    • ldresult2 == ((long double)fresult1+fresult2)/2. 「正しい」答えは fresult1 です。

詳細はどこか間違っているかもしれませんが、これはおそらく、デノルムを取得したときに経験しなければならない苦痛です.

そして、別の問題にぶつかります。sqrt() が異なる実装間で同じ resolt を返すという保証はないと確信しています (trig 関数については非常に確実です)。私が今まで見た唯一の保証は、結果が「1 ulp 以内」(おそらく正しく丸められた結果) であることです。これは使用されるアルゴリズムに大きく依存しており、最新の CPU にはこれらの命令があるため、ソフトウェアで実装しようとすると、パフォーマンスが大幅に低下します。それにもかかわらず、ISTRは一貫性を実現するはずの「ポータブル」浮動小数点ライブラリのどこかにありましたが、OTTOMHという名前を覚えていません。

于 2010-10-03T03:15:57.207 に答える