29

浮動小数点計算には精度の問題があり、その理由を説明する多くの質問があることを理解しています。私の質問は、同じ計算を 2 回実行した場合、常に同じ結果が得られるということですか? これに影響を与える要因は何ですか?

  • 計算間の時間?
  • CPUの現在の状態?
  • ハードウェアが違う?
  • 言語/プラットフォーム/OS?
  • 太陽フレア?

簡単な物理シミュレーションがあり、再生できるようにセッションを記録したいと考えています。計算が信頼できる場合は、初期状態とユーザー入力を記録するだけでよく、常に最終状態を正確に再現できるはずです。計算が正確でない場合、開始時のエラーがシミュレーションの終了までに大きな影響を与える可能性があります。

私は現在 Silverlight で作業していますが、この質問に一般的に答えられるかどうか知りたいです。

更新: 最初の回答は「はい」を示していますが、選択した回答のコメントで説明されているように、明らかにこれは完全に明確ではありません。いくつかのテストを行って、何が起こるかを確認する必要があるようです。

4

10 に答える 10

24

私が理解していることから、同じ命令セットとコンパイラを扱っていて、実行するプロセッサが関連する標準 (IEEE754) に厳密に準拠している場合にのみ、同一の結果が保証されます。とはいえ、特に混沌としたシステムを扱っていない限り、実行間の計算のずれがバグの原因になることはほとんどありません。

私が知っている特定の落とし穴:

  1. 一部のオペレーティング システムでは、互換性を損なう方法で浮動小数点プロセッサのモードを設定できます。

  2. 浮動小数点の中間結果は、多くの場合、レジスタでは 80 ビット精度を使用しますが、メモリでは 64 ビットしか使用しません。関数内のレジスタ スピルを変更する方法でプログラムを再コンパイルすると、他のバージョンとは異なる結果が返される場合があります。ほとんどのプラットフォームでは、すべての結果を強制的にメモリ内の精度に切り詰める方法が提供されます。

  3. 標準ライブラリ関数は、バージョン間で変更される場合があります。gcc 3 対 4 で、珍しくはない例がいくつかあると思います。

  4. IEEE 自体は、いくつかのバイナリ表現が異なることを許可しています...具体的には NaN 値ですが、詳細を思い出せません。

于 2008-11-30T08:51:32.353 に答える
20

簡単な答えは、 IEEE Floating Point Standardに従って、FP 計算は完全に決定論的であるということですが、それはマシン、コンパイラ、OS などで完全に再現できるという意味ではありません。

これらの質問に対する長い答えとその他の詳細は、おそらく浮動小数点に関する最良のリファレンスである David Goldberg のWhat Every Computer Scientist Should Know About Floating Point Arithmeticにあります。主要な詳細については、IEEE 標準のセクションに進んでください。

箇条書きに簡単に答えるには:

  • 計算間の時間と CPU の状態は、これとはほとんど関係がありません。

  • ハードウェアが影響する場合があります (たとえば、一部の GPU は IEEE 浮動小数点に準拠していません)。

  • 言語、プラットフォーム、および OS も影響を与える可能性があります。これについて私が提供できるよりも詳しい説明については、Jason Watkins の回答を参照してください。Java を使用している場合は、Java の浮動小数点の不備に関する Kahan の暴言を参照してください。

  • 太陽フレアは問題になるかもしれません。私はあまり心配していません。これは、 EMPを心配することと同じカテゴリに入れます。

最後に、同じ初期入力に対して同じ一連の浮動小数点計算を実行している場合、問題なく正確に再生できるはずです。正確なシーケンスは、コンパイラ/OS/標準ライブラリによって変わる可能性があるため、この方法でいくつかの小さなエラーが発生する可能性があります.

通常、浮動小数点で問題が発生するのは、数値的に不安定なメソッドを使用し、ほぼ同じであるが完全ではないFP 入力から開始する場合です。メソッドが安定していれば、ある程度の許容範囲内で再現性を保証できるはずです。これ以上の詳細が必要な場合は、上にリンクされている Goldberg の FP 記事を参照するか、数値解析の紹介テキストを参照してください。

于 2008-11-30T08:33:04.713 に答える
8

あなたの混乱は、浮動小数点に関する不正確さのタイプにあると思います。ほとんどの言語は、IEEE 浮動小数点標準を実装しています。この標準は、float/double 内の個々のビットを使用して数値を生成する方法を示しています。通常、float は 4 バイトと double 8 バイトで構成されます。

2 つの浮動小数点数の間の数学演算は、(標準で指定されているように) 毎回同じ値になります。

不正確さは精度にあります。int と float を考えてみましょう。通常、どちらも同じバイト数 (4) を使用します。しかし、各数値が保存できる最大値は大きく異なります。

  • int: 約 20 億
  • float: 3.40282347E38 (かなり大きい)

違いは真ん中です。int は、0 から約 20 億までのすべての数値を表すことができます。ただし、フロートはできません。0 から 3.40282347E38 までの 20 億の値を表すことができます。しかし、それでは表現できない値の全範囲が残ります。数式がこれらの値のいずれかに該当する場合、表現可能な値に四捨五入する必要があるため、「不正確」と見なされます。不正確の定義は異なる場合があります:)。

于 2008-11-30T08:38:49.493 に答える
4

また、Goldbergは優れたリファレンスですが、元のテキストも間違っています: IEEE754 is not gaurented to be Portable . この声明がテキストのスキミングに基づいて作成される頻度を考えると、これを十分に強調することはできません. ドキュメントの以降のバージョンには、これについて具体的に説明するセクションが含まれています。

多くのプログラマーは、IEEE 標準で規定された数値形式と演算のみを使用するプログラムでも、異なるシステムでは異なる結果を計算できることに気付いていない可能性があります。実際、標準の作成者は、異なる実装で異なる結果が得られるようにすることを意図していました。

于 2008-11-30T09:01:17.170 に答える
2

申し訳ありませんが、誰もが要点を見逃していると思わざるを得ません。

不正確さがあなたがしていることにとって重要な場合は、別のアルゴリズムを探す必要があります。

計算が正確でない場合、最初のエラーがシミュレーションの終わりまでに大きな影響を与える可能性があるとあなたは言います。

私の友人はシミュレーションではありません。丸めと精度によるわずかな違いが原因で非常に異なる結果が得られる場合は、有効な結果が得られない可能性があります。結果を繰り返すことができるからといって、それが有効になるわけではありません。

測定値や非整数計算を含む重要な実世界の問題では、小さなエラーを導入して、アルゴリズムがどれほど安定しているかをテストすることを常にお勧めします。

于 2008-11-30T09:12:07.973 に答える
2

あなたの質問には C# のタグが付けられているため、.NET で直面する問題を強調する価値があります。

  1. 浮動小数点演算は結合的で(a + b) + cはありません。つまり、等しいとは保証されませんa + (b + c)
  2. さまざまなコンパイラがさまざまな方法でコードを最適化し、それには算術演算の並べ替えが含まれる場合があります。
  3. .NET では、CLR の JIT コンパイラがコードをオンザフライでコンパイルするため、コンパイルは実行時のマシン上の .NET のバージョンに依存します。

これは、異なるバージョンの .NET CLR で実行した場合に、.NET アプリケーションが同じ浮動小数点計算結果を生成することに依存してはならないことを意味します。

たとえば、あなたのケースでは、シミュレーションへの初期状態と入力を記録してから、CLR を更新するサービス パックをインストールすると、次に実行したときにシミュレーションが同じように再生されない場合があります。

Shawn Hargreaves のブログ投稿Is floating point math deterministic?を参照してください。.NET に関連する詳細な議論については。

于 2011-04-19T06:57:21.750 に答える
1

HM。OPがC#を要求したので:

C#バイトコードJITは決定論的ですか、それとも異なる実行間で異なるコードを生成しますか?わかりませんが、Jitは信用できません。

JITにある程度のサービス品質機能があり、CPUが他の場所で大量の処理を行っているため(バックグラウンドDVDエンコーディングを考えてください)、最適化に費やす時間を減らすことにしたシナリオを考えることができますか?これは微妙な違いにつながる可能性があり、後で大きな違いが生じる可能性があります。

また、JIT自体が改善された場合(おそらくサービスパックの一部として)、生成されたコードは確実に変更されます。80ビットの内部精度の問題についてはすでに説明しました。

于 2008-11-30T13:41:51.563 に答える
0

これはあなたの質問に対する完全な答えではありませんが、C# での double 計算が非決定論的であることを示す例を次に示します。理由はわかりませんが、一見無関係なコードが下流の double 計算の結果に明らかに影響を与える可能性があります。

  1. Visual Studio バージョン 12.0.40629.00 Update 5 で新しい WPF アプリケーションを作成し、すべての既定のオプションを受け入れます。
  2. MainWindow.xaml.cs の内容を次のように置き換えます。

    using System;
    using System.Windows;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                Content = FooConverter.Convert(new Point(950, 500), new Point(850, 500));
            }
        }
    
        public static class FooConverter
        {
            public static string Convert(Point curIPJos, Point oppIJPos)
            {
                var ij = " Insulated Joint";
                var deltaX = oppIJPos.X - curIPJos.X;
                var deltaY = oppIJPos.Y - curIPJos.Y;
                var teta = Math.Atan2(deltaY, deltaX);
                string result;
                if (-Math.PI / 4 <= teta && teta <= Math.PI / 4)
                    result = "Left" + ij;
                else if (Math.PI / 4 < teta && teta <= Math.PI * 3 / 4)
                    result = "Top" + ij;
                else if (Math.PI * 3 / 4 < teta && teta <= Math.PI || -Math.PI <= teta && teta <= -Math.PI * 3 / 4)
                    result = "Right" + ij;
                else
                    result = "Bottom" + ij;
                return result;
            }
        }
    }
    
  3. ビルド構成を「リリース」に設定してビルドしますが、Visual Studio では実行しません。

  4. ビルドされたexeをダブルクリックして実行します。
  5. ウィンドウに「Bottom Insulated Joint」が表示されていることに注意してください。
  6. 「string result」の直前に次の行を追加します。

    string debug = teta.ToString();
    
  7. 手順 3 と 4 を繰り返します。

  8. ウィンドウに「Right Insulated Joint」が表示されていることに注意してください。

この動作は、同僚のマシンで確認されました。次のいずれかに該当する場合、ウィンドウには一貫して「Right Insulated Joint」が表示されることに注意してください: exe が Visual Studio 内から実行された場合、exe がデバッグ構成を使用してビルドされた場合、またはプロジェクト プロパティで「32 ビットを優先」がオフになっている場合。

プロセスを観察しようとすると結果が変わるように見えるため、何が起こっているのかを理解するのは非常に困難です。

于 2016-03-04T00:27:31.140 に答える
-4

IEEE 標準を満たす FPU はほとんどありません (その主張にもかかわらず)。したがって、異なるハードウェアで同じプログラムを実行すると、実際には異なる結果が得られます。その結果は、ソフトウェアで FPU を使用することの一部として既に回避すべきまれなケースである可能性があります。

多くの場合、IEEE のバグはソフトウェアにパッチが適用されています。現在実行しているオペレーティング システムには、製造元からの適切なトラップとパッチが含まれていると確信していますか? OS の更新前または更新後はどうなりますか? すべてのバグが削除され、バグ修正が追加されていますか? C コンパイラはこれらすべてと同期しており、C コンパイラは適切なコードを生成していますか?

これをテストしても無駄かもしれません。製品を納品するまで問題は発生しません。

FP ルール番号 1 を観察してください: if(something==something) 比較を使用しないでください。そして、ルール番号2のIMOは、asciiからfpまたはfpからascii(printf、scanfなど)に関係する必要があります。ハードウェアよりも精度とバグの問題があります。

ハードウェア (密度) が新世代になるたびに、太陽の影響がより顕著になります。惑星表面の SEU にはすでに問題があるため、浮動小数点計算とは別に、問題が発生することになります (気にするベンダーはほとんどいないため、新しいハードウェアではより頻繁にクラッシュすることが予想されます)。

膨大な量のロジックを消費することにより、fpu は非常に高速 (1 クロック サイクル) になる可能性があります。整数 alu より遅くはありません。これを最新の fpu と混同しないでください。fpu は高価です。(同様に、乗算と除算のためにより多くのロジックを消費して、それを1クロックサイクルに減らしますが、fpuほど大きくはありません)。

上記の単純なルールを守り、浮動小数点をもう少し勉強し、浮動小数点に伴ういぼやトラップを理解してください。無限大または nans を定期的にチェックすることをお勧めします。問題は、ハードウェアよりもコンパイラとオペレーティング システムで見つかる可能性が高くなります (一般に、fp 数学だけではありません)。現代のハードウェア (およびソフトウェア) は、定義上、最近ではバグだらけです。

于 2008-11-30T15:59:46.497 に答える