9

This one prints 100:

int j=2;
int i= pow(10,2);  
printf("%d\n", i);

and this one prints 99:

int j=2;
int i= pow(10,j);  
printf("%d\n", i);

Why?

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 6
    What compiler are you using and on what system? – Shafik Yaghmour Oct 01 '13 at 22:12
  • 1
    My guess is this is integer truncation of the double result, it would be interesting to see what the `"%f"` output looks like. – Shafik Yaghmour Oct 01 '13 at 22:16
  • One has a literal argument and the other an non-literal argument. So different code is called with different precisions. For example `gcc` has a `pow` builtin called when the arguments are both literals. In this case it would use the builtin for the first program and call the library function for the second program. – ouah Oct 01 '13 at 22:34
  • mingw (devc++) on windows 7 ultimate 64bit – Rimgaudas Tumėnas Oct 01 '13 at 22:37
  • possible duplicate of [pow() cast to integer, unexpected result](http://stackoverflow.com/questions/18417788/pow-cast-to-integer-unexpected-result) – Eric Postpischil Oct 01 '13 at 23:37
  • Nice try to blame Microsoft, but this is GCC compiling for x86-64. Up to the actual call of `pow`, there is not a single bit (literally) for which Microsoft is responsible. Fully a GCC deficiency, then. – MSalters Oct 02 '13 at 07:19
  • 1
    @MSalters: No, it's definitely MS's fault, or rather mingw's fault for using buggy MS code. Mingw is a C implementation using GCC as the compiler and MSVCRT.DLL (Microsoft's libc) as the standard library. The buggy `pow` is part of the latter. – R.. GitHub STOP HELPING ICE Oct 03 '13 at 04:31
  • @R.. : Reread the question. The difference is not the `pow` call, but the initialization of its arguments (via literal versus variable). IEEE 754 does not require `pow` to be bit-perfect (only `+-/* sqrt`) so the Microsoft implementation is standards compliant. – MSalters Oct 03 '13 at 07:30
  • 1
    @MSalters: As stated, it maybe conforming, but even if so, it's an extremely low quality of implementation. There's no justification for making a function return wrong results for arguments where the correct result is exactly representable and trivial to compute correctly. The compiler's choice of optimizations explains the discrepency, but there would not have been any discrepency had the library version returned the correct result. – R.. GitHub STOP HELPING ICE Oct 03 '13 at 14:13
  • @R..: Different implementations have different tradeoffs. Another important property of `pow(x,y)` is that `pow(x1,y) > pow(x2,y)` if `x1>x2 && y2>1`. Special-casing some values may break this. – MSalters Oct 03 '13 at 14:37
  • 1
    @MSalters: That property, as stated with strict inequality, is impossible to satisfy by a simple counting argument; the only way it could be true is if `pow(x,y)==x` for all x,y. If you fix it to use `<=` instead of `<`, then any sane implementation handling exact results correctly would satisfy your (modified) condition. – R.. GitHub STOP HELPING ICE Oct 04 '13 at 03:55
  • You Can Refer To This http://stackoverflow.com/questions/42164550/what-is-happening-here-in-pow-function – Suraj Jain Feb 19 '17 at 07:41
  • Possible duplicate of [Why does gcc compiler output pow(10,2) as 99 not 100?](https://stackoverflow.com/questions/25474351/why-does-gcc-compiler-output-pow10-2-as-99-not-100) – phuclv Apr 09 '19 at 08:25
  • duplicates: [Why does pow(5,2) become 24?](https://stackoverflow.com/q/22264236/995714), [Why pow(10,5) = 9,999](https://stackoverflow.com/q/9704195/995714) – phuclv Jul 31 '21 at 16:48

3 Answers3

14

What's going on is that you have a C implementation whose standard library has a very low quality implementation of pow which is returning inexact results even when the exact result is representable in the type (double). The call to pow(10,2) seems to producing the value just below 100.0, which, when rounded to an integer, yields 99. The reason you don't see this when the arguments are constant is that the compiler took the liberty to optimize out the call alltogether and replace it with a constant 100 at compiletime.

If your intent is to do integer powers, don't use the pow function. Write a proper integer power function, or when the exponent is known, just write out the multiplication directly.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Yes, even if pow library does compute exact result properly rounded, relying on every integer to be represented exactly in double is fragile. I'm waiting the avent of 64 bits int to ask why pow(11,18) is not properly computed. – aka.nice Oct 02 '13 at 01:49
  • 1
    In practice it's safe from that standpoint. `int` will never change in practical (non-DSP) implementations due to many issues related to unexpected effects of integer promotion, the problems of omitting one size step from the standard types, and simply plain legacy compatibility. – R.. GitHub STOP HELPING ICE Oct 02 '13 at 01:53
2

In the first case, I suspect the compiler has optimized the value to 10*10 without actually calling pow (compilers do actually do this). In the second case, it looks like you have a floating-point rounding error. The result is almost 100 but not quite, and the implicit cast to int truncates it.

The pow function operates on double, not int.

In general (but not always), when you convert doubles to integers, you call round(). Eg:

int i = (int) round(pow(10,j));

If your C library doesn't have this, you can emulate:

#define round(x) floor((x)+0.5)
Adam
  • 16,808
  • 7
  • 52
  • 98
paddy
  • 60,864
  • 6
  • 61
  • 103
0

pow returns double and so if the result is not exactly 100 but slightly less than it will truncate when converting to an int and you will receive the 99 result you are seeing. It would be interesting to see what the results look like for a double variable and %f format.

The reason you won't see it when you use literals is because of constant folding which will cause the call to pow to be optimized out and replaced with a constant. We can see the version that uses constants when we generate the assembly no call to pow is made it just moves the end result 100(see it live):

movl    $100, -4(%rbp)

while the version the second version actually calls pow(see it live):

call    pow
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740