19

I can't explain the behaviour of the following program (compiled with gcc on mingw 32 bits). I'm aware of the possible precision loss when implicitly converting from double to int, but I would expect the two cases to give the same output since it is doing the exact same operations. Why are the two outputs different?

#include <stdio.h>
#include <math.h>

int main()
{
    int table[3] = {2, 3, 4};
    int i, N;

    N = 0;
    N += table[0] * pow(100, 0);
    N += table[1] * pow(100, 1);
    N += table[2] * pow(100, 2);
    printf("%d\n", N);

    N = 0;
    for(i = 0; i < 3; i++)
        N += table[i] * pow(100, i);
    printf("%d\n", N);

    return 0;
}

//output: 
40302
40300
Étienne
  • 4,773
  • 2
  • 33
  • 58

1 Answers1

14

With pow(100, 0) pow(100, 1) and pow(100, 2) the compiler replaces the function calls with constants (1, 100, 10000), but with pow(100, i) it has to actually call the function at runtime (because of the variable i being passed as argument), resulting with two results of pow in the form 0.99999999 and 99.999999 instead of 1 and 100 (or any 2 of the 3). When truncating to int after the multiply you "lose" two units.

This is another example of why converting to int from double is just pure evil: very hard to find subtle bugs in your program (not compiler bugs).

Btw, I am surprised that the compiler with O2 didn't unroll the loop, propagate the constants and reach the same optimization (replacing the function call with constant results).

Btw2 Scratch that, I am surprised that the compiler didn't just replace all you code with only two calls to printf.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • I think it's worth mentioning that the C standard actually doesn't specify the precision of "pow()", not even that "pow()" has to give the same result for pow(0) and pow(i) with i=0. That was really surprising for me but makes sense to allow for optimizations on very small embedded systems. – Étienne Oct 05 '16 at 14:03
  • Interestingly, the compiler [optimized this away when the loop has only two iterations](https://godbolt.org/z/q3GzW6). – vgru Dec 02 '19 at 13:01
  • @Groo Your link points to a different compiler (gcc 9.2 x86-64), so it is not really surprising that the result is different. Even with three iterations in the loop the result of my question cannot be reproduced with gcc 9.2, my question was specific to mingw-32bits GCC. – Étienne Aug 07 '20 at 10:48