Search code examples
c++doubleprecisioncoutieee

Lowest double positive value - can cout change its value?


Consider two following pieces of code - the only difference between them is a single cout which prints the value eps:
http://ideone.com/0bEeHz - here the program enters and infinite loop since after the cout eps changes value to 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 - here I've commented out the 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;
}


Hence, one single cout changes program logic dramatically and very surprisingly. Why is that?


Solution

  • I think it's a case of Section 5 (Expressions), paragraph 11

    The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.

    at work, cf. this variation of the original code.

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

    Calculations and comparisons performed at extended precision. The loop runs until eps is the smallest positive extended value (probably the 80-bit x87 extended type).

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

    Still at extended precision, eps != 0

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

    For the conversion to a string to print, eps is stored and converted to double precision, resulting in 0.

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

    Yes, now it is.