Finding the perfect pth power of a number using Java when the number is a fraction

1.2k Views Asked by At

We say p is the perfect pth power of a number x if x can be expressed as another number b^p.

i.e if x=b^p , then p is the perfect pth power of x.

I have few use cases where x can be either a positive integer, negative integer or even a fraction. The first two cases can be handled easily in java, but how to find out the perfect pth power of a number x using java, when x is a fraction. Is it not true that if x is a fraction, we can simply use Math.sqrt(x) and get a number b such that b^2 =x? Then 2 will be the perfect pth power of x. Is this case even valid?

I am not necessarily looking for code, but the logic to determine the perfect pth power of x in java if x is a fraction. Also please do state your reason if anyone thinks this case is invalid.

Below is the code I wrote to handle cases where x is either a positive integer or a number between 0 and 1. But can we handle cases where x is, say for eg. 45.487,875515.54884, etc?

public class PerfectPower {

public PerfectPower() {

    }

    public Integer getPerfectPower(double x){

        // x=b^p

        int p = 0;
        double b;

        if(x==0){
            throw new IllegalArgumentException("Cannot accept number 0.");
        }

        if (x > 1) {
            for (b = 2; b <= x; b++) {

                double value = 0;
                p = 1;

                while (value <= x) {

                    value = Math.pow(b, p);

                    if (value == x) {
                        return p;
                    } else if (value > x) {
                        break;
                    } else {
                        p++;
                    }
                }

            }
        } else if(x>0 && x<1){

            for (b = 2; (1/b) >= x; b++) {

                double value = 1;
                p = -1;

                while (value >= x) {

                    value = Math.pow(b, p);

                    if (value == x) {
                        return p;
                    } else if (value < x) {
                        break;
                    } else {
                        p--;
                    }
                }

            }

        }

        return null;

    }
2

There are 2 best solutions below

0
On

We can do this in a simple way using logarithms. It goes as below:

x = b^p    log(base b)x = p     log x/log b = p  

So we can iterate b = 2 through x and check whether p is a perfect integer and return the value. For decimal cases we can tweak the log formula some more.

log b = (log x)/p    Hence b = 10^(log x)/p) 

In each iteration we can check whether b^p = x and if it is return p. I solved this problem assuming p should be an integer. However for cases where p can be decimal and x between 0 to 1 this solution should be tweaked some more. Below is my code which I have implemented in scala.

def perfectpowerlog(x: Double): Double = {
    var i: Double = 2
    var n: Double = 1
    var p: Double = 0
    val loop = new Breaks
    if (x == 1) {
        return n
    }
    if (x.ceil == x) {
        loop.breakable {
            while (i<=x) {
                p = math.log(x)/math.log(i)
                if (p.toInt == p) {
                    n = p
                    loop.break()
                }
                else
                    i=i+1
            }
        }
    }
    else {
        loop.breakable {
            while(i<=x.ceil) {
                p = pow(10,(log10(x)/i))
                if(pow(p,i) == x) {
                    n = i
                    loop.break()
                }
                else
                    i = i+1
            }
        }
    }
    return n
}
0
On

Since 45 487.875 515 548 84 (to take this as an example) is not integral, the only way it can be expressed as b ^ p where b and p are integral, is if p is negative. That is, your number may be the square root, the cube root, the fourth root, etc., of some (large) integer.

The first question is that of precision. Your number cannot be represented precisely in a Java double. You may use a BigDecimal. It also cannot be precisely some root of some integer, so you will have to decide a tolerance to accept.

As far as I can tell, your big problem is that the range of possible p values is infinite. It may even be so that all numbers are close enough to the pth root of some (large) integer that you cannot reasonably distinguish; I don’t know, and it surely depends on your tolerance.

I think the best thing you can try is to raise your number to 2, 3, 4, etc., and see when you come close to a whole number. If your number raised to the power of q is close enough to a whole number, return -q as your p. And stop searching before you lose your patience. :-)