-2

When I use the pow() function, sometimes the results are off by one. For example, this code produces 124, but I know that 5³ should be 125.

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

int main(){
    int i = pow(5, 3);
    printf("%d", i);
}

Why is the result wrong?

princebillyGK
  • 2,917
  • 1
  • 26
  • 20
  • 1
    https://stackoverflow.com/questions/588004/is-floating-point-math-broken Using float pow() for int is rarely predictable. – Yunnosch Nov 21 '17 at 06:49
  • 3
    Implement a version of `pow` in your program to work with integral input. That will prevent the problems of using floating point math. – R Sahu Nov 21 '17 at 06:51
  • 3
    Looks like a perfect opportunity to learn how to use a debugger. – Jesper Juhl Nov 21 '17 at 06:53
  • If the program is in C please don’t tag C++ since it’s not relevant. – Sami Kuhmonen Nov 21 '17 at 06:53
  • There must be a duplicate for problems with `(int) pow()`... – Yunnosch Nov 21 '17 at 06:54
  • `pow` uses [logarithms](https://stackoverflow.com/questions/41072787/why-is-powint-int-so-slow/41078483) to calculate x^y, and log is calculated thanks to series which sometimes gets a bit higher results, sometimes (your case) a bit lower. – Déjà vu Nov 21 '17 at 06:54
  • 7
    @JesperJuhl: I doubt a debugger would help much here. He's already identified the location of the problem, and it's a standard library function, the code of which may not even be available (and it probably wouldn't help much even if it was). – Benjamin Lindley Nov 21 '17 at 06:56

4 Answers4

9

Your problem is that you are mixing integer variables with floating point math. My bet is that the result of 5^3 is something like 124.999999 due to rounding problems and when cast into integer variable get floored to 124.

There are 3 ways to deal with this:

  1. more safely mix floating math and integers

    int x=5,y=3,z;
    z=floor(pow(x,y)+0.5);
    // or
    z=round(pow(x,y));
    

    but using this will always present a possible risk of rounding errors affecting the result especially for higher exponents.

  2. compute on floating variables only

    so replace int with float or double. This is a bit safer than #1 but still in some cases is this not usable (depends on the task). and may need occasional floor,ceil,round along the way to get the wanted result correctly.

  3. Use integer math only

    This is the safest way (unless you cross the int limit). The pow can be computed on integer math relatively easily see:

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • 1
    (1) is safe up to the 53rd power of 2 for IEEE754 `double`, and is an elegant fix. (2) is a bad idea, (3) by far the best, so +2/3. – Bathsheba Nov 21 '17 at 08:04
  • @Bathsheba Yes and they state the same. But there are tasks where the #1,#2 approaches are enough or even preferred but all depends on the task and target accuracy – Spektre Nov 21 '17 at 08:05
3

pow(x, y) is most likely implemented as exp(y * log(x)): modern CPUs can evaluate exp and log in a couple of flicks of the wrist.

Although adequate for many scientific applications, when truncating the result to an integer, the result can be off for even trivial arguments. That's what is happening here.

Your best bet is to roll your own version of pow for integer arguments; i.e. find one from a good library. As a starting point, see The most efficient way to implement an integer based power function pow(int, int)

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

Use Float Data Type

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

int main()
{
    float x=2;
    float y=2;
    float p= pow(x,y);
    printf("%f",p);
    return 0;
}
Sujikanth
  • 133
  • 1
  • 1
  • 7
  • Prefer `double` instead. Notice that before the variables get sent to the functions that use them, they are automatically converted to `double`. – pmg May 20 '20 at 11:04
-3

You can use this function instead of pow:

long long int Pow(long long int base, unsigned int exp)
{
    if (exp > 0)
        return base * Pow(base, exp-1);
    return 1;
}
goodvibration
  • 5,980
  • 4
  • 28
  • 61
  • 3
    It will be better to use a looping implementation instead of a recursive implementation. – R Sahu Nov 21 '17 at 06:56
  • 2
    Hopefully the stack will resist a high exp – Déjà vu Nov 21 '17 at 06:56
  • @RSahu: Yes, that's also an option. There are other options as well, even more efficient, which run in `O(log(exp))`, but I figured that this dude's main problem was correctness rather than performance. – goodvibration Nov 21 '17 at 06:58
  • SO has a bunch of implementations already, to calculate int^int – Déjà vu Nov 21 '17 at 06:59
  • @ringø: And hopefully the `long long int` will "resist" a high `exp` (in terms of wrap-around). I think, though, that this is not the main issue that this dude's question is all about... – goodvibration Nov 21 '17 at 06:59
  • @goodvibration, performance and stack problems aside, a looping implementation is probably easier to follow for a beginner. – R Sahu Nov 21 '17 at 06:59
  • @RSahu: Yes, that one I do agree with :) – goodvibration Nov 21 '17 at 07:00
  • @ringø: No, with regards to the `long long int` - I do mean in terms of wrap-around. A stack overflow would occur due to the recursive implementation, not due to the type being used. – goodvibration Nov 21 '17 at 07:02
  • Never said that :-) Of course SO would occur due to recursivity. – Déjà vu Nov 21 '17 at 07:03
  • @ringø: Ohhhhhh, You used "SO" for this website's name!!! Damn. OK, sorry for the misunderstanding. BTW, still, not sure what the point in that comment. Of course there are plenty of integer solutions here, as in other places (Google, etc). – goodvibration Nov 21 '17 at 07:06
  • 2
    Probably the worst `Pow` implementation I've seen in a while. – Bathsheba Nov 21 '17 at 08:02