Question

I have the next function:

static bool isPowerOf(int num, int power)
{
        double b = 1.0 / power;
        double a = Math.Pow(num, b);
        Console.WriteLine(a);
        return a == (int)a;
}

I inserted the print function for analysis.

If I call the function:

isPowerOf(25, 2)

It return true since 5^2 equals 25. But, if I call 16807, which is 7^5, the next way:

isPowerOf(16807, 5)

In this case, it prints '7' but a == (int)a return false.

Can you help? Thanks!

Was it helpful?

Solution

Try using a small epsilon for rounding errors:

return Math.Abs(a - (int)a) < 0.0001;

As harold suggested, it will be better to round in case a happens to be slightly smaller than the integer value, like 3.99999:

return Math.Abs(a - Math.Round(a)) < 0.0001;

OTHER TIPS

Comparisons that fix the issue have been suggested, but what's actually the problem here is that floating point should not be involved at all. You want an exact answer to a question involving integers, not an approximation of calculations done on inherently inaccurate measurements.

So how else can this be done?

The first thing that comes to mind is a cheat:

double guess = Math.Pow(num, 1.0 / power);
return num == exponentiateBySquaring((int)guess, power) ||
       num == exponentiateBySquaring((int)Math.Ceil(guess), power);
       // do NOT replace exponentiateBySquaring with Math.Pow

It'll work as long as the guess is less than 1 off. But I can't guarantee that it will always work for your inputs, because that condition is not always met.

So here's the next thing that comes to mind: a binary search (the variant where you search for the upper boundary first) for the base in exponentiateBySquaring(base, power) for which the result is closest to num. If and only if the closest answer is equal to num (and they are both integers, so this comparison is clean), then num is a power-th power. Unless there is overflow (there shouldn't be), that should always work.

Math.Pow operates on doubles, so rounding errors come into play when taking roots. If you want to check that you've found an exact power:

  • perform the Math.Pow as currently, to extract the root
  • round the result to the nearest integer
  • raise this integer to the supplied power, and check you get the supplied target. Math.Pow will be exact for numbers in the range of int when raising to integer powers

If you debug the code and then you can see that in first comparison:

isPowerOf(25, 2) 

a is holding 5.0 Here 5.0 == 5 => that is why you get true

and in 2nd isPowerOf(16807, 5)

a is holding 7.0000000000000009

and since 7.0000000000000009 != 7 => you are getting false. and Console.WriteLine(a) is truncating/rounding the double and only show 7

That is why you need to compare the nearest value like in Dani's solution

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top