Search code examples
c++while-loopcastingtype-conversion

Why does this loop behaves different depending on int value?


I'm trying to understand why is this while loop iterating sometimes 16 times, sometimes it is infinite loop (e.g. when i == 10^8) and sometimes not iterating at all (e.g. when i == 10^9).

#include <iostream>

using namespace std;

int main() {
    int i;
    cin >> i;
    float x = i;
    while (x < (float)(i + 16)) {
        cout << x << endl;
        x++;
    }

    return 0;
}

I have tried to translate float numbers to binary IEE 754 representation, but still don't find answer why is this happening.


Solution

  • Because 100000000 and 100000001 as the same representation in float32. But 100000000 and 100000016 haven't.

    So, you enter the loop, but then the ++ is void.

    On the other hand 1000000000 and 1000000016 have the same representation in float32. So you don't even enter the loop.

    In python (it may be strange to reply with python code to C++ question ; just because it is an interpreter, so it is faster to show quick examples ; but after all, you specify two different languages, C and C++, so I had to fail at least one of those languages, why not two. And it shows that the problem is related to 32 bits float representation, not to the language itself)

    x=1e8
    np.float32(x+16)-x
    # 16 (note that np.float32(x) is 100000020. But same numerical error make 100000020-100000000=16
    np.float32(x+1)-x
    # 0 
    x=1e9
    np.float32(x+16)-x
    # 0
    np.float32(x+1)-x
    # 0
    

    In detail, 1e9 is represented by bits
    01001110 01101110 01101011 00101000 in 32 bits floats.

    First 0 is sign (positive). Then, we have 8 bits of exponent 10011100 = 156. Since this is relative to 127, that is 29. Then we have an implicit 1, followed by 23 bits of mantissa. So 111011100110101100101000. Which is 1+1/2+1/4+0/8+1/16+...+0/2²³ 1.862645149230957. So altogether, +1.862645149230957×2²⁹ = 10⁹

    We already knew that it was 1e9. It is just to establish that we understand what those bits mean.

    And to do the same for the next number. Next number in that representation is
    01001110 01101110 01101011 00101001

    Likewise, sign +, exponent 29, and mantissa, same +1 111011100110101100101001 = 1+1/2+1/4+0/8+...+0/2²²+1/2²³ = 1.8626452684402466. So altogether, next number is 1000000064.0

    In other words, there is nothing between 1000000000 and 1000000064 (or to be more accurate, nothing "different". All numbers in between are synonyms either of 1000000000 or of 1000000064, from 32 bits float perspective)