39

私は今日、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操作を実行するために何を使用できますか?

4

4 に答える 4

29

x87の最大の問題は、基本的にすべてのレジスタ操作が80ビットで行われるのに対し、ほとんどの場合、64ビット浮動小数点数(倍精度浮動小数点数)しか使用しないことです。何が起こるかというと、64ビットのfloatをx87スタックにロードすると、80ビットに変換されます。80ビットでいくつかの操作を実行してから、メモリに格納して64ビットに変換します。たった64ビットですべての操作を行った場合とは異なる結果が得られます。最適化コンパイラを使用すると、値が何回変換されるかが非常に予測できないため、「回帰テストを行うときの「正解」の答え。

アセンブリを作成する人(またはコンパイラのコードジェネレータを作成する場合は間接的にアセンブリを作成する)の観点からのみ重要なもう1つの問題は、x87がレジスタスタックを使用するのに対し、SSEは個別にアクセス可能なものを使用することです。レジスタ。x87を使用すると、スタックを操作するための追加の命令がたくさんあります。IntelとAMDは、追加のスタック操作x87命令を高速に実行するよりも、SSEコードを使用してプロセッサを高速に実行する方がよいと思います。

ところで、不正確さの問題がある場合は、「すべてのプログラマーが浮動小数点演算について知っておくべきこと」の記事を見て、代わりに任意精度の数学ライブラリー(GMPなど)を使用することをお勧めします。

于 2010-07-10T15:43:45.497 に答える
5

拡張精度の数学を適切に使用するには、中間計算の結果を格納するために使用でき、それらの結果を生成する式の代わりに使用できる型を言語がサポートしている必要があります。したがって、与えられた:

void print_dist_squared(double x1, double y1, double x2, double y2)
{
  printf("%12.6f", (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}

x2-x1一般的な部分式とをキャプチャして置き換えるために使用できるタイプが必要です。これy2-y1により、コードを次のように書き直すことができます。

void print_dist_squared(double x1, double y1, double x2, double y2)
{
  some_type dx = x2-x1;
  some_type dy = y2-y1;
  printf("%12.6f", dx*dx + dy*dy);
}

プログラムのセマンティクスを変更せずに。残念ながら、ANSI Cは拡張精度計算を実行するプラットフォームで使用できるタイプを指定できず、some_typeANSIのサポートの失敗を非難するよりも、拡張精度タイプの存在をIntelに非難することがはるかに一般的になりました。

実際、拡張精度型は、浮動小数点ユニットのないプラットフォームでも、x87プロセッサの場合と同じくらいの価値があります。このようなプロセッサでは、x + y+zのような計算には次の手順が必要になるためです。

  1. 仮数、指数、および場合によってはxの符号を別々のレジスタに解凍します(指数と符号は多くの場合「ダブルバンク」になる可能性があります)
  2. 同様にyを開梱します。
  3. 指数が低い場合は、値の仮数を右シフトしてから、値を加算または減算します。
  4. xとyの符号が異なる場合は、左端のビットが1になるまで仮数を左シフトし、指数を適切に調整します。
  5. 指数と仮数をdouble形式に戻します。
  6. その一時的な結果を解凍します。
  7. zを開梱します。
  8. 指数が低い場合は、値の仮数を右シフトしてから、値を加算または減算します。
  9. 以前の結果とzの符号が異なる場合は、左端のビットが1になるまで仮数を左シフトし、指数を適切に調整します。
  10. 指数と仮数をdouble形式に戻します。

拡張精度タイプを使用すると、ステップ4、5、および6を省略できます。53ビットの仮数は大きすぎて4つ未満の16ビットレジスタまたは2つの32ビットレジスタに収まらないため、64ビットの仮数で加算を実行するのは53ビットの仮数を使用するよりも遅くはありません。拡張精度の数学は、一時的な結果を保持するための適切な型をサポートする言語で、欠点のない高速な計算を提供します。非FPUチップで最も効率的な方法である方法で浮動小数点演算を実行できるFPUを提供したことで、Intelを責める理由はありません。

于 2015-09-21T23:20:00.320 に答える
3

もう1つの答えは、80ビットの精度を使用することは悪い考えであることを示唆しているようですが、そうではありません。それは、不正確さを寄せ付けないために時々重要な役割を果たします。たとえば、W。カハンの著作を参照してください。

速度的に問題を解決できる場合は、常に80ビットの中間演算を使用してください。それがx87数学を使用しなければならないことを意味するなら、まあ、そうしてください。それに対するサポートは至る所にあり、人々が正しいことをし続ける限り、それは至る所にあり続けるでしょう。

于 2015-09-21T15:39:06.883 に答える
0

二重精度はf80(約2.5ニブル/桁)より11ビット少なく、多くのアプリ(主にゲーム)では問題ありません。ただし、宇宙プログラムや医療アプリなどで利用できるすべての精度が必要になります。

f80がスタック上で動作している(そしてそれによって落胆している)と言う人がいると、少し誤解を招きます。FPUレジスタとスタック操作に似た操作、おそらくそれが人々を混乱させるものです。これは、実際にはメモリベース(ロード/ストア)であり、スタック自体ではありません。たとえば、実際にスタックを介してパラメータを渡すcdeclstdcallのような呼び出し規約とは異なります。そしてそれは何も悪いことではありません。

SSEの大きな利点は、実際には、2、4、8の値を一度にシリアル化することであり、多くのバリアン操作があります。はい、レジスタに直接転送できますが、最後にその値をメモリに転送します。

f80の大きな欠点は、奇数の10バイト長であるため、アライメントが中断されることです。アクセスを高速化するには、それらを16に揃える必要があります。しかし、アレイには実際には実用的ではありません。

三角法やその他のトランスデンタル数学演算には、fpuを使用する必要があります。asmの場合、本当に楽しくて便利なf80のトリックがたくさんあります。

ゲームや通常のシンプルなアプリ(ほぼすべて)の場合、誰かを死なせることなく、ダブルを使用することができます。しかし、いくつかの深刻な数学または科学的なアプリでは、f80を捨てることはできません。

于 2016-09-09T01:51:30.557 に答える