1

本当に奇妙です:

double *data; // uncorrelated
double a,b,c;
double sigma = 1e-309; // denormalized number

try { data = new double[10]; } // uncorrelated
catch(...) { cout << "error"; return 1; }

a = 1/sigma;                    // infinite
b = exp(-1/sigma);              // 0
c = a * b;                      // NaN
cout << c << endl;
c = (1/sigma) * exp(-1/sigma);  // 0
cout << c << endl;

いくつかの最適化により、2 番目の c の結果が 0 になる可能性があります。

BUT : try/catch ブロックを削除すると、2 番目の c は NaN のままです! なぜこの異なる動作??? 私のコンパイラは VC++ 2010 Express です。OS Windows7 64ビット。iostream や cmath などの標準ライブラリのみを使用します。

編集:私の最初の観察は、空のコンソールアプリケーションのDebug + Win32デフォルト設定でした。Release+Win32 では、結果は次のとおりです。最初の c 0、2 番目の c NaN - try/catch が存在するかどうかに関係なく! 概要:

                                 //Debug+Win32              // Release+Win32
                              //with try   //without     //with try   //without
c = a * b;                     // NaN         NaN             0           0
c = (1/sigma) * exp(-1/sigma); // 0           NaN            NaN         NaN

編集 2 : /fp:strictC++/コード生成でスイッチを設定すると、結果は Debug+Win32 と同じですが、Release+Win32 では、try の有無に関係なく、c = a * b; // NaNに変わります。Debug+Win32 のc = (1/sigma) * exp(-1/sigma); // 0ままで、先行試行がない理由がわかりません。前の試行に応じてNaN+NaN結果がリリースと異なる場合、浮動小数点セーフでなければならないプログラムをデバッグする方法は?/fp:strict

編集3:ここに完全なプログラムがあります:

// On VC++ 2010 Express in default Win32-Debug mode for empty console application.
// OS: Windows 7 Pro 64-Bit, CPU: Intel Core i5.
// Even when /fp:strict is set, same behaviour.
//
// Win32-Release mode: first c == 0, second c == NaN (independent of try)
// with /fp:strict: first c == NaN, second c == 0 (also independent of try)

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    double *data; // uncorrelated
    double a,b,c;
    double sigma = 1e-309; // denormalized number

    try { data = new double[10]; } // uncorrelated
    catch(...) { cout << "error"; return 1; }

    a = 1/sigma;                    // infinite
    b = exp(-1/sigma);              // 0
    c = a * b;                      // NaN
    cout << c << endl;
    c = (1/sigma) * exp(-1/sigma);  // 0 with preceding try or
    cout << c << endl;              // NaN without preceding try

    cin.get();
    return 0;
}
4

1 に答える 1

2

このようなことは、レジスタの割り当て/使用方法の違いによって発生する可能性があります。たとえば、try-catch ブロックを使用すると、 の値がsigma64 ビットとして保存されてdoubleからメモリから再ロードされる可能性がありますが、ブロックがないと、より高精度の 80 ビット レジスタが使用される可能性があります ( http://en. wikipedia.org/wiki/Extended_precision ) を 64 ビットに丸めません。気になる場合は、アセンブリを確認することをお勧めします。

于 2013-11-19T10:04:48.747 に答える