3
#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
Jabberwocky
  • 40,411
  • 16
  • 50
  • 92
user541396
  • 131
  • 2
  • 1
    Looks like a rounding problem – Jabberwocky Feb 05 '21 at 16:19
  • `pow` works with floating-point number, it's generally not guaranteed to return an exact answer. Here, you round its return value (probably something like `99.9999999999`) down and get `99` instead of `100`. See https://stackoverflow.com/questions/588004/is-floating-point-math-broken/ – yeputons Feb 05 '21 at 16:21
  • @Jabberwocky if its a rounding problem, why only in odd exponentials and when function is outside of a loop, why is it working as it should. – user541396 Feb 05 '21 at 16:21
  • 1
    `pow` is meant for use on floating point, don't use it for integers. – Nate Eldredge Feb 05 '21 at 16:21
  • What is you output if you replace `int place_value` with `double place_value` and `printf("%d \n", place_value)` with `printf("%lf \n", place_value)`? – Jabberwocky Feb 05 '21 at 16:21
  • 2
    In your second example the compiler might decide to optimize the code by completely removing the call to `pow` and using `1000` instead. That is not possible in a loop – Gerhardh Feb 05 '21 at 16:22
  • @Jabberwocky 1.000000 10.000000 100.000000 1000.000000 10000.000000 – user541396 Feb 05 '21 at 16:23
  • 2
    Still, given that the result of `pow(10, 2)` can be represented exactly as `double` (unless your machine is very weird), you would hope that `pow` would be implemented well enough to give that result. What compiler and system is this? – Nate Eldredge Feb 05 '21 at 16:23
  • @Gerhardh It might not be allowed to do that for numerical reasons unless you disable the strict floating point mode. – Ian Abbott Feb 05 '21 at 16:24
  • @NateEldredge I am using Win10 64 bit i5, on VScode text editor. I don't know how to check compiler. – user541396 Feb 05 '21 at 16:26
  • What compiler are you using? I get the correctly-rounded results with gcc and clang. – Paul Hankin Feb 05 '21 at 16:27
  • 2
    Try `round(pow(10, loop))` – Jabberwocky Feb 05 '21 at 16:27
  • 1
    @IanAbbott: Strict floating-point does not preclude optimizing `pow(10, 3)` to `1000`: The result is exact, not dependent on rounding mode, not affected by rules about infinities or NaNs, and does not raise any exception flags. So replacing it by `1000` does not violate any strictness requirements. – Eric Postpischil Feb 05 '21 at 16:28
  • @PaulHankin How to check compiler ? – user541396 Feb 05 '21 at 16:28
  • @EricPostpischil Though it would be confusing if it returns different results depending on whether `pow` gets optimized out or not. Maybe a quality of implementation issue? – Ian Abbott Feb 05 '21 at 16:29
  • @IanAbbott: Yes, it is a quality of implementation issue. `pow` can reasonably be implemented with error less than 1 ULP. (The ideal is correct rounding, which has error at most ½ ULP, but that is hard.) Apple’s `pow` has sub-ULP accuracy, and a consequence of that is that whenever the mathematical result is exactly representable, it is returned. So Apple’s `pow(10, loop)` returns exact answers for `loop` in [0, 27], after which the exact answers are not representable (if I got that upper bound right). – Eric Postpischil Feb 05 '21 at 16:36
  • [Why does pow(5,2) become 24?](https://stackoverflow.com/q/22264236/995714), [Why does pow(n,2) return 24 when n=5, with my compiler and OS?](https://stackoverflow.com/q/25678481/995714) – phuclv Feb 05 '21 at 16:56

3 Answers3

5

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.

Eric Postpischil
  • 141,624
  • 10
  • 138
  • 247
  • Is there a better alternative than pow? It is the only result i got searching for exponential function. – user541396 Feb 05 '21 at 16:30
  • 3
    @user541396: Since you are just using powers incrementally, start with `int p = 1;` and multiply `p` by ten in each iteration of the loop. – Eric Postpischil Feb 05 '21 at 16:32
  • 2
    @user541396: Perhaps surprisingly, there is no standard function for this, but https://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int describes a lot of possible options. A reasonable first approach would be a simple multiplication loop with special handling for the bases `0, 1, -1`. – Nate Eldredge Feb 05 '21 at 16:33
  • @user541396 or simply use `round` like this: `round(pow(10, loop))` – Jabberwocky Feb 05 '21 at 16:33
  • 1
    I was just about to vote to close the question as still another duplicate of "Is floating point math broken?" (since in many ways, it is) but then I read this answer. It seems sufficiently informative that the question is best left open. – John Coleman Feb 05 '21 at 16:41
  • @JohnColeman A [merge](https://meta.stackexchange.com/questions/158066/what-is-a-merged-question) would be better. – Andrew Henle Feb 05 '21 at 17:34
  • @EricPostpischil smart implementations check for those most popular bases or exponents and not always choose this longest path :). – 0___________ Feb 05 '21 at 17:44
1

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))
Jabberwocky
  • 40,411
  • 16
  • 50
  • 92
Theepag
  • 193
  • 1
  • 11
0

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];
}
0___________
  • 34,740
  • 4
  • 19
  • 48