3

考虑以下两段代码 - 它们之间的唯一区别是单个 cout 打印值 eps: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;
}


因此,一个单一的 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 回答