私の本質的な問題は、クラシック 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 に同じ結果を提供することはできませんでしたが、統計的に許容できるほど十分に近いものでした。専門家のユーザーが関心のある領域を選択することによって処理が導かれ、ユーザーの入力がモデルの進行状況に部分的に反応することを考えると、主任科学者はそれが受け入れられると判断しました (これは一晩で決定されたわけではありません!)。残りの数値の違いは、さまざまな臨床結果を決定するものの範囲内にあるため、テストではさまざまな診断が見られません.