問題タブ [x87]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
floating-point - 80 ビットの拡張精度データ型のアプリケーションと利点は何ですか?
ええ、私は80-bitと言うつもりでした。あれはタイプミスじゃない…
私の浮動小数点変数の経験では、single (32 ビット)、double (64 ビット)、long double (96 ビットまたは 128 ビットと呼ばれる) などの 4 バイトの倍数が常に関係していました。そのため、 AIFF (Audio Interchange File Format) ファイルを読み書きするコードを作成しているときに、 80 ビットの拡張精度データ型に遭遇したとき、少し混乱しました。サンプリングを格納するために拡張精度変数が選択されました。オーディオトラックのレート。
ウィキペディアをざっと見てみると、 IEEE 754-1985 標準の概要に 80 ビット形式の簡単な言及と共に上記のリンクが見つかりました(ただし、IEEE 754-2008 標準の概要にはありません)。特定のアーキテクチャでは、「extended」と「long double」は同義語のようです。
私が遭遇していないことの 1 つは、拡張精度データ型 (もちろん、AIFF ファイルのサンプリング レートを除く) を利用する特定のアプリケーションです。これにより、私は疑問に思いました:
- 一部のプログラミングアプリケーションで拡張精度が必要/有益である状況に遭遇した人はいますか?
- 明らかな「double よりも精度が高いが、long double のほとんどの実装よりもバイト数が少ない」以外に、80 ビット浮動小数点数の利点は何ですか?
- その適用性は薄れていますか?
x86 - SSE に対する x87 の利点
x87 の方が内部精度が高いことはわかっています。これは、おそらく x87 と SSE 操作の最大の違いです。しかし、x87 を使用する利点は他にあるのでしょうか? 私はどのプロジェクトでも自動的に入力する習慣があり-mfpmath=sse
、x87 FPU が提供する他の機能が欠けているのではないかと考えています。
c++ - NaNのシグナリングの有用性?
私は最近、IEEE754とx87アーキテクチャについてかなり読みました。作業中の数値計算コードでNaNを「欠落値」として使用することを考えていました。シグナリングNaNを使用すると、必要のない場合に浮動小数点例外をキャッチできるようになることを期待していました。 「欠落している値」に進みます。逆に、私は静かなNaNを使用して、「欠落値」が計算を通じて伝播できるようにします。ただし、NaNのシグナリングは、NaNに存在する(非常に限られた)ドキュメントに基づいて機能すると思っていたようには機能しません。
これが私が知っていることの要約です(これはすべてx87とVC ++を使用しています):
- _EM_INVALID(IEEEの「無効な」例外)は、NaNに遭遇したときのx87の動作を制御します
- _EM_INVALIDがマスクされている(例外が無効になっている)場合、例外は生成されず、操作はクワイエットNaNを返すことができます。NaNのシグナリングを伴う操作では、例外はスローされませんが、クワイエットNaNに変換されます。
- _EM_INVALIDがマスクされていない(例外が有効になっている)場合、無効な操作(sqrt(-1)など)により、無効な例外がスローされます。
- x87はシグナリングNaNを生成しません。
- _EM_INVALIDがマスクされていない場合、シグナリングNaNを使用すると(変数を初期化する場合でも)、無効な例外がスローされます。
標準ライブラリは、NaN値にアクセスする方法を提供します。
と
問題は、NaNのシグナリングには何の役にも立たないということです。_EM_INVALIDがマスクされている場合、それはクワイエットNaNとまったく同じように動作します。他のNaNに匹敵するNaNはないため、論理的な違いはありません。
_EM_INVALIDがマスクされていない(例外が有効になっている)場合、変数をシグナリングNaNで初期化することもできません。
double dVal = std::numeric_limits<double>::signaling_NaN();
これは例外をスローするためです(シグナリングNaN値がx87レジスタにロードされ、メモリアドレスに格納されます)。
あなたは私がしたように次のことを考えるかもしれません:
- マスク_EM_INVALID。
- シグナリングNaNを使用して変数を初期化します。
- Unmask_EM_INVALID。
ただし、手順2ではシグナリングNaNがクワイエットNaNに変換されるため、その後使用しても例外はスローされません。だからWTF?!
シグナリングNaNに何か有用性や目的はありますか?元々の目的の1つは、それを使用してメモリを初期化し、単一化された浮動小数点値の使用をキャッチできるようにすることであったことを理解しています。
私がここで何かが足りないかどうか誰かに教えてもらえますか?
編集:
私がやりたかったことをさらに説明するために、ここに例を示します。
データのベクトル(double)に対して数学演算を実行することを検討してください。一部の操作では、ベクトルに「欠落値」を含めることができます(たとえば、一部のセルに値がないが、それらの存在が重要であるスプレッドシート列に対応していると仮定します)。一部の操作では、ベクトルに「欠落値」が含まれることを許可したくありません。セットに「欠落値」が存在する場合は、おそらく別のアクションを実行したいと思います。おそらく、別の操作を実行します(したがって、これは無効な状態ではありません)。
この元のコードは次のようになります。
「欠落値」のチェックは、ループの反復ごとに実行する必要があることに注意してください。私はほとんどの場合理解していますが、sqrt
関数(または他の数学演算)はこのチェックを覆い隠す可能性があり、演算が最小限(おそらく単なる加算)であり、チェックにコストがかかる場合があります。「欠落値」が正当な入力値を無効にし、計算が合法的にその値に到達した場合にバグを引き起こす可能性があるという事実は言うまでもありません(そうではないかもしれませんが)。また、技術的に正確であるためには、ユーザー入力データをその値と照合し、適切な措置を講じる必要があります。私は、このソリューションがエレガントでなく、パフォーマンス的に最適ではないと感じています。これはパフォーマンスが重要なコードであり、並列データ構造やある種のデータ要素オブジェクトの贅沢は絶対にありません。
NaNバージョンは次のようになります。
これで、明示的なチェックが削除され、パフォーマンスが向上するはずです。FPUレジスタに触れずにベクトルを初期化できれば、これですべてうまくいくと思います...
さらに、自尊心のあるsqrt
実装がNaNをチェックし、すぐにNaNを返すことを想像します。
delphi - 8087CW モードの変更による System.Move のメモリ破損 (png + stretchblt)
奇妙なメモリ破損の問題があります。何時間もデバッグして試した後、何かを見つけたと思います。
例: 簡単な文字列割り当てを行います。
ただし、結果が次のようになる場合があります。
したがって、_ は 0 バイトに置き換えられます。
System.Move 関数で、高速メモリ コピーに FPU スタック (fild、fistp) を使用する場合 (9 バイトから 32 バイトまで移動する場合)、これが 1 回発生するのを見たことがあります (タイミングによっては、再現が難しい場合があります)。
FPU ビューと 2 つのメモリ デバッグ ビュー (Delphi -> View -> Debug -> CPU -> Memory) を使用すると、うまくいかないことがわかりました...一度...再現できませんでしたが...
今朝、私は 8087CW モードについて何か読みました。はい、これを $27FI に変更すると、メモリが破損します! 通常は $133F です。
$133F と $027F の違いは、$027F が FPU を設定して、精度の低い計算 (Extended ではなく Double に制限) と、異なる無限処理 (古い FPU で使用されていましたが、現在は使用されていません) を行うことです。
さて、理由はわかりましたが、いつではありません!
簡単なチェックでAsmProfilerの動作を変更しました(そのため、すべての関数は出入り時にチェックされます)。
いくつかのユニットと dll とビンゴを「プロファイリング」しました (スタックを参照):
だから、それは StretchBlt で起こっています...
今何をする?Windows のせいですか、それとも PNG のバグですか (D2007 に含まれています)。または、System.Move 関数はフェイルセーフではありませんか?
注:単純に再現しようとしてもうまくいきません:
それはもっとエキゾチックなようです...しかし、「Get8087CW = $27F」のデバッグブレークにより、別の文字列で再現できました: FPU パート 1:
FPU パート 2:
FPU パート 3:
FPU 最終: 破損!:
注 2: System.Move で FPU スタックをクリアする必要があるのではないでしょうか?
floating-point - SSE2ではなくx87の拡張(80ビット)倍精度浮動小数点-見逃しませんか?
私は今日、NVidiaのPhys-Xライブラリがx87FPとSSE2を使用していることを発見した研究者について読んでいました。明らかに、これは速度が精度よりも優先される並列データセットには最適ではありません。ただし、記事の著者は次のように引用しています。
Intelは2000年後半にP4の導入によりx87の使用を推奨し始めました。x86-64はSSE2サポートで定義されているため、AMDは2003年のK8以降x87を非推奨にしました。VIAのC7は2005年からSSE2をサポートしています。64ビットバージョンのWindowsでは、x87はユーザーモードでは非推奨であり、カーネルモードでは完全に禁止されています。業界のほぼすべての人が2005年以来x87よりもSSEを推奨しており、ソフトウェアを組み込みPentiumまたは486で実行する必要がない限り、x87を使用する理由はありません。
私はこれについて疑問に思いました。x87は内部で80ビットの拡張doubleを使用して値を計算しますが、SSE2は使用しません。これは誰にとっても重要ではありませんか?それは私には驚きのようです。平面内のポイント、ライン、ポリゴンを計算する場合、減算を行うと値が驚くほど間違っている可能性があり、精度が不足しているために領域が崩壊し、ラインが相互にエイリアスする可能性があります。80ビット値と64ビット値を使用すると役立つと思います。
これは間違っていますか?そうでない場合、x87が段階的に廃止された場合、拡張ダブルFP操作を実行するために何を使用できますか?
assembly - 浮動小数点演算にはどのような命令を使用する必要がありますか?
私は、x86アセンブリで浮動小数点数を操作するためのx87命令にある程度精通しています。しかし、私はどこかでこれらがもうめったに使われなくなったことを読みました。(64ビットWindowsドライバーでは許可されていませんでした)[ 1 ]
その場合、どのような指示を使用する必要がありますか?私はSSEについて何かを見ましたが、私が間違えない限り、それらの指示はずっと最近追加されたものであり、古いチップでは利用できません。(Pentium IIなどのように)
どのような指示を使用する必要がありますか?
assembly - この単純なプログラムがなぜこれほど多くの文字を出力するのですか?
これが私の短いアセンブリプログラムです:
プログラムが実行することになっているのは5.5を出力することですが、次のように出力します。
-4101885043414705786563701568963176764603483495211119243453355953219830430011006780068899468997203661787555969981250050126586203424320244681571103387315766489883301796219461838644670607029711305942610787622864198879363376953745160639821663444829839767678538571371627347101810056161000273217639447052410683392.000000
一体何が間違っているのですか?コードは2つの引数をにプッシュしてprintf()
から呼び出しています。複雑なことは何もありません。
更新:私はこれを修正したと考えるのに少し時期尚早でした。コードを更新しました。
assembly - FPUスタックから何かを削除する最も簡単な方法
最近、FPUスタックオーバーフローで問題が発生しています。呼び出されるたびにガベージ値をFPUスタックにプッシュし、クリーンアップしないバグのあるライブラリ関数まで追跡することができました。
幸いなことに、これは簡単に再現でき、どのような条件が原因であるかを正確に把握しています。インラインASMのブロックを、このルーチンを呼び出すルーチンにドロップして、FPUスタックから最上位の値をポップバックすることができます...何を書くべきかよくわからない場合を除きます。私のASM-fuは中途半端なものですが、それほど強力ではありません。
では、x86アセンブリでFPUスタックの最上位の値を削除する最も簡単な方法は何ですか?それがガベージデータであり、値を気にしないと仮定しますか?
floating-point - 近い浮動小数点数間の「離散」差を見つける
2 つの浮動小数点数 と がx
ありy
、それらの値が非常に近いとします。
コンピューターで表現できる浮動小数点数には離散的な数があるため、それらを昇順で列挙できます: f_1, f_2, f_3, ...
. x
このリストでとの距離を見つけたいですy
(つまり、それらは 1、2、3、... またはn
個別のステップで離れていますか?)
算術演算 ( +-*/
) のみを使用し、バイナリ表現を見ないでこれを行うことは可能ですか? 私は主に、これが x86 でどのように機能するかに興味があります。
それとそれとがほんの数ステップ(たとえば、100未満)離れていると仮定するy > x
と、次の近似は正しいですか?(おそらくない...)x
y
ここでeps
、マシンのイプシロンを示します。(マシン イプシロンは、1.0 と次に小さい浮動小数点数との差です。)
c - インライン アセンブリで即値浮動小数点数を指定するにはどうすればよいですか?
このコードをコンパイルしようとすると:
次のエラーが表示されます。
なぜこれが機能しないのですか?浮動小数点演算で数値「150」をスタックにプッシュできないのはなぜですか?