1

この小さなコードは私を夢中にさせます:

#include <stdio.h>

    int main() 
{
double x;
const double d=0.1;
x=d ;
for (int i=0; i<30; i++) 
    {
    printf("Cycle %d  Value :%.20e \n",i,x);
    x=x*(double)11.-(double)10*d; //11*0.1 = 1.1 - 10*0.1 = 1 => 0.1

    }       
return 0;
}

実際、私はIEEE 754規格の浮動小数点数の内部表現による病理学的ケースを実証しようとしていました. MacOS または Windows マシンでは、最終的な出力行は次のようになります。

サイクル 29 値 :1.28084153156127500000e+13

しかし、Linux (Scientific Linux 5.4) では、コードは問題なく実行されます。読んで、次のことがわかりました。

FreeBSD、NetBSD、OpenBSD などの BSD システムでは、ハードウェアの倍精度丸めモードがデフォルトであり、ネイティブの倍精度プラットフォームとの最大の互換性を提供します。x86 GNU/Linux システムでは、デフォルトのモードは拡張精度です (精度を高めることを目的としています)。

同じページのGCC INTROでは、Linux システムで倍精度丸めを有効にする方法が説明されていましたが、他のシステムで拡張精度を使用する方法については説明されていませんでした。MacOsまたはWindowsでそれは可能ですか? そしてどうやって ?

4

1 に答える 1

3

OS X で拡張精度を使用するのは簡単です。

x=11.L*x - 10.L*d;

L接尾辞により、2 つのリテラルがslong doubleではなくdoubles になり、式全体が C の式評価規則に従って拡張された 80 ビットで評価されるようになります。

それはさておき、あなたの質問には混乱があるようです。「... Linux では、コードは問題なく実行されます」と言います。いくつかのポイント:

  • OS X の結果と Linux の結果はどちらも、IEEE-754 と C 標準に準拠しています。どちらにも「問題」はありません。
  • OS X の結果は、(非標準の) 80 ビット浮動小数点型をサポートしないハードウェアで再現可能です。Linux の結果はそうではありません。
  • 中間結果が 80 ビット拡張で保持されることに依存する計算は脆弱です。コンパイラ オプション、最適化設定、またはプログラム フローを変更すると、結果が変わる場合があります。OS X の結果は、このような変更が行われても安定しています。

最終的に、浮動小数点演算は実際の演算ではないことに注意する必要があります。Linux で得られた結果が実数で式を評価したときに得られた結果に近いという事実は、そのアプローチをより良く (またはより悪く) しません。

拡張精度の自動使用が浮動小数点の素朴なユーザーを救ったすべてのケースで、その評価モードの予測不可能性が微妙で診断が難しいバグを導入したケースを示すことができます。これらは一般に「過剰精度」バグと呼ばれます。最近の最も有名な例の 1 つは、ユーザーが2.2250738585072011e-308Web フォームに入力してサーバーをクラッシュさせるバグでした。究極の原因は、まさにコンパイラーがプログラマーの背後に隠れて、指示されたよりも高い精度を維持していることにあります。倍精度式は拡張ではなく倍精度で評価されるため、OS X はこのバグの影響を受けませんでした。

システムが再現可能で移植可能である限り、人々は浮動小数点演算の落とし穴について教育を受けることができます。double で倍精度式を評価し、single で単精度式を評価すると、これらの属性が提供されます。拡張精度評価を使用すると、それらが損なわれます。ツールが予測できない環境では、本格的なエンジニアリングを行うことはできません。

于 2011-10-07T12:46:39.957 に答える