3

次の2つのコードを考えてみましょう-それらの唯一の違いは、値epsを出力する単一のcoutです:http:
//ideone.com/0bEeHz-ここで、cout epsが値を0に変更した後、プログラムが無限ループに入ります

#include <iostream>

int main()
{
    double tmp = 1.;
    double eps;
    while(tmp != 0) {
        eps = tmp;
        tmp /= 2.;
    }
    if(eps == 0) {
        std::cout << "(1)eps is zero!\n";
    }
    std::cout << "eps before: " << eps;
    if(eps == 0) {
        std::cout << "(2)eps is zero!\n";
    }

    while(eps < 1.) {
        tmp = eps;
        eps *= 2.;
        if(tmp == eps) {
            printf("wtf?\n");
        }
    }

    std::cout << "eps after: " << eps;
}


http://ideone.com/pI4d30-ここで私はcoutをコメントアウトしました。

#include <iostream>

int main()
{
    double tmp = 1.;
    double eps;
    while(tmp != 0) {
        eps = tmp;
        tmp /= 2.;
    }
    if(eps == 0) {
        std::cout << "(1)eps is zero!\n";
    }
    //std::cout << "eps before: " << eps;
    if(eps == 0) {
        std::cout << "(2)eps is zero!\n";
    }

    while(eps < 1.) {
        tmp = eps;
        eps *= 2.;
        if(tmp == eps) {
            printf("wtf?\n");
        }
    }

    std::cout << "eps after: " << eps;
}


したがって、1つのcoutがプログラムロジックを劇的にそして非常に驚くべきことに変更します。何故ですか?

4

1 に答える 1

2

セクション5(式)、段落11の場合だと思います

浮動オペランドの値と浮動式の結果は、型で必要とされるよりも高い精度と範囲で表すことができます。それによって型が変更されることはありません。

職場で、参照。元のコードのこのバリエーション。

while(tmp != 0) {
    eps = tmp;
    tmp /= 2.;
}

拡張精度で実行される計算と比較。ループepsは、最小の正の拡張値 (おそらく 80 ビット x87 拡張型) になるまで実行されます。

if(eps == 0) {
    std::cout << "(1)eps is zero!\n";
}

それでも拡張精度で、eps != 0

std::cout << "eps before: " << eps;

出力する文字列への変換では、epsが格納されてdouble精度に変換され、結果は 0 になります。

if(eps == 0) {
    std::cout << "(2)eps is zero!\n";
}

はい、今です。

于 2012-11-03T16:06:59.503 に答える