10

同じ64ビット浮動小数点数で同じ操作を行うと、最新のPCや最も一般的なプログラミング言語でまったく同じ結果が得られると想定できるかどうかを知りたいのですが。(C ++、Java、C#など)。数値を操作していて、結果も数値であると想定できます(NaN、INFなどはありません)。

浮動小数点数を使用した計算には、非常によく似た2つの標準(IEEE854-1987とIEEE754-2008)があることを私は知っています。しかし、それが実際にどのように行われているのかはわかりません。

4

7 に答える 7

8

64ビット浮動小数点を実装する最新のプロセッサは、通常、IEEE 754-1985標準に近いものを実装し、最近754-2008標準に取って代わられました。

754標準は、特定の基本操作、特に加算、減算、乗算、除算、平方根、および否定からどのような結果を得る必要があるかを指定します。ほとんどの場合、数値結果は正確に指定されます。結果は、丸めモードで指定された方向(最も近い、無限大、ゼロ、または負の無限大)で正確な数学結果に最も近い表現可能な数値である必要があります。「最も近い」モードでは、標準はタイがどのように切断されるかも指定します。

このため、オーバーフローなどの例外条件を伴わない操作では、標準に準拠するさまざまなプロセッサで同じ結果が得られます。

ただし、異なるプロセッサで同じ結果を得るのを妨げるいくつかの問題があります。それらの1つは、コンパイラーがさまざまな方法で浮動小数点演算のシーケンスを自由に実装できる場合が多いことです。たとえば、Cで「a = b c + d」と記述した場合、すべての変数がdoubleとして宣言されているため、コンパイラは「b」を自由に計算できます。倍精度演算またはより範囲や精度の高いもののいずれかでc"。たとえば、プロセッサに拡張精度浮動小数点数を保持できるレジスタがあり、拡張精度で演算を実行する場合、CPU時間はそれ以上かかりません。倍精度で演算を行う場合、コンパイラは拡張精度を使用してコードを生成する可能性があります。このようなプロセッサでは、別のプロセッサと同じ結果が得られない場合があります。コンパイラがこれを定期的に行っても、そうではない場合があります。複雑なシーケンス中にレジスタがいっぱいになるため、中間結果が一時的にメモリに格納される場合があります。そうすると、拡張精度の数値ではなく、64ビットのdoubleだけが書き込まれる可能性があります。したがって、浮動小数点演算を含むルーチンは、おそらく1つの場所にインライン化された異なるコードでコンパイルされ、コンパイラーが別のレジスターを必要としたという理由だけで、異なる結果をもたらす可能性があります。

一部のプロセッサには、乗算と加算を1つの命令で計算する命令があるため、「b c + d」は中間丸めなしで計算され、最初にbcを計算してからdを加算するプロセッサよりも正確な結果が得られる場合があります。

コンパイラには、このような動作を制御するためのスイッチがある場合があります。

754-1985標準が一意の結果を必要としない場所がいくつかあります。たとえば、アンダーフローが発生したかどうか(結果が小さすぎて正確に表現できない)を判断する場合、標準では、実装が仮数(小数ビット)を目標精度に丸める前または後に判断を行うことができます。したがって、一部の実装では、他の実装では発生しないのにアンダーフローが発生したことが示されます。

プロセッサの一般的な機能は、「ほぼIEEE 754」モードを備えていることです。これにより、標準で必要とされる非常に小さな数値を返す代わりに、ゼロを置き換えることでアンダーフローを処理する難しさが解消されます。当然、このようなモードで実行すると、より準拠したモードで実行した場合とは異なる数値が得られます。非準拠モードは、パフォーマンス上の理由から、コンパイラやオペレーティングシステムによってデフォルトで設定されている場合があります。

IEEE 754の実装は通常、ハードウェアだけでなく、ハードウェアとソフトウェアの組み合わせによって提供されることに注意してください。プロセッサは作業の大部分を実行する場合がありますが、特定の例外の処理、特定のモードの設定などをソフトウェアに依存しています。

基本的な算術演算を超えてサインやコサインなどに移行する場合、使用するライブラリに大きく依存します。超越関数は通常、注意深く設計された近似で計算されます。実装はさまざまなエンジニアによって独自に開発され、互いに異なる結果が得られます。あるシステムでは、sin関数は、小さい引数(pi程度未満)の場合はULP(最小精度の単位)内で正確な結果を提供しますが、大きい引数の場合は大きなエラーを返します。別のシステムでは、sin関数により、すべての引数についていくつかのULP内で正確な結果が得られる場合があります。現在の数学ライブラリは、すべての入力に対して正しく丸められた結果を生成することが知られていません。この目標に向けていくつかの良い仕事をしたプロジェクト、crlibm(Correctly Rounded Libm)があります。

要約すると、管理可能な一連の計算があり、コンパイラの実装を理解し、非常に注意している場合は、異なるプロセッサで同じ結果を信頼できます。そうでなければ、完全に同一の結果を得るのはあなたが信頼できるものではありません。

于 2010-01-27T21:26:25.570 に答える
7

まったく同じ結果を得るという意味であれば、答えはノーです。

同じマシンでのデバッグ(最適化されていない)ビルドとリリースビルド(最適化された)で異なる結果が得られる場合もあるため、異なるマシンで結果が常に同じであるとは限りません。

(これは、たとえばIntelプロセッサを搭載したコンピュータで、オプティマイザが中間結果の変数をレジスタに保持し、最適化されていないビルドでメモリに格納されている場合に発生する可能性があります。IntelFPUレジスタは80ビットであり、double変数は64であるためビット、中間結果は最適化されたビルドでより高い精度で保存され、後の結果で異なる値を引き起こします。)

ただし、実際には、同じ結果が得られることがよくありますが、それに依存するべきではありません。

于 2010-01-27T20:28:26.283 に答える
2

最新のFPUはすべて、IEEE754フロートをシングルフォーマットとダブルフォーマットで実装し、一部は拡張フォーマットで実装しています。特定の一連の操作がサポートされており(のほとんどすべてmath.h)、いくつかの特別な命令がそこに浮かんでいます。

于 2010-01-27T20:12:29.843 に答える
1

同じC#プログラムは、最適化なしでデバッグモードでコンパイルされた後、最適化が有効になっているリリースモードでコンパイルされた後、同じPC上で異なる数値結果を引き出すことができます。それが私の個人的な経験です。プログラムの1つに自動回帰テストスイートを初めて設定したときは、これを考慮していませんでした。多くのテストが明確な理由なしに失敗したことに完全に驚いていました。

于 2010-01-27T20:28:06.590 に答える
1

複数の操作を適用することについて話していると仮定すると、正確な数が得られるとは思いません。CPUアーキテクチャ、コンパイラの使用、最適化設定により、計算結果が変わります。

(アセンブリレベルでの)操作の正確な順序を意味する場合でも、バリエーションが得られると思います。たとえば、Intelチップは内部で拡張精度(80ビット)を使用しますが、他のCPUには当てはまらない場合があります。(拡張精度は必須ではないと思います)

于 2010-01-27T20:13:13.633 に答える
1

x86のC#の場合、80ビットのFPレジスタが使用されます。

C#標準では、プロセッサは型自体と同じかそれ以上の精度で動作する必要があるとされています(つまり、「double」の場合は64ビット)。ストレージを除いて、プロモーションは許可されます。つまり、ローカルとパラメータは64ビットを超える精度である可能性があります。

言い換えると、メンバー変数をローカル変数に割り当てることで、不等式を与えるのに十分である可能性があります(実際、特定の状況下ではそうなります)。

参照:デバッグ/リリースモードでの浮動小数点/倍精度

于 2010-01-27T20:36:24.777 に答える
0

64ビットデータ型の場合、使用されているIEEE 754の「倍精度」/「binary64」(1985年と2008年はここではあまり違いはありません)しか知りません。

注:IEEE 854-1987で定義されている基数タイプは、いずれにせよIEEE754-2008に置き換えられます。

于 2010-01-27T20:14:12.023 に答える