Why is pow() function in C giving wrong answer when it is odd exponential of 10 in a loop?

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

int main()
{
    int loop, place_value=0, c = 5;
    for(loop = 0; loop < c; loop++)
    {
        place_value = 0;
        place_value = pow(10, loop);
        printf("%d \n", place_value);
    }
    return 0;
}

This code gives

10 
99 
1000 
9999 

Why is 99 and 9999 there in 3rd and 5th line instead of 100 and 10000 respectively?

When asking for power normally, it gives right answer.

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

int main()
{
  printf ("%d", (int) pow (10,3 ));
  return 0;
}
1000
3 Answers

pow is a difficult routine to implement, and not all implementations give good results. Roughly speaking, the core algorithm for pow(x, y) computes a logarithm from (a part of) x, multiplies it by y, and computes an exponential function on the product. Doing this in floating-point introduces rounding errors that are hard to control.

The result is that the computed result for pow(10, 4) may be something near 10,000 but slightly less or greater. If it is less, than converting it to an integer yields 9999.

When you use arguments hard-coded in source code, the compiler may compute the answer during compilation, possibly using a different algorithm. For example, when y is three, it may simply multiply the first argument by itself, as in x*x*x, rather than using the logarithm-exponent algorithm.

As for why the low result happens with the odd numbers you have tested, consider what happens when we multiply 5.45454545 by various powers of 10 and round to an integer. 5.45454545 rounds down to 5. 54.5454545 rounds up to 55. 545.454545 rounds down to 545. The rounding up or down is a consequence of what fraction happens to land beyond the decimal point. For your cases with pow(10, loop), the bits of the logarithm of 10 may just happen to give this pattern with the few odd numbers you tried.

pow(x, y) function translate more or less to exp(log(x) * y), which will give a result that is not quite the same as x ^ y.

In order to solve this issue you can round this:

round(pow(x, y))

The rule of thumb: never use floating point functions (especially such a complicated ones like pow or log) with integer numbers.

Simply implement integer pow

unsigned intpow(unsigned x)
{
    unsigned result = 1;
    while(x --) result *= 10;
    return result;
}

it will be much faster or even (the fastest one)

int intpow1(unsigned x)
{
    const static unsigned vals[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, /* ... */};

    #if defined(CHECK_OVERFLOW)
    if(x >= sizeof(vals)/ sizeof(vals[0])) return -1;
    #endif

    return vals[x];
}
Related