I was trying to get a cubic root in java using Math.pow(n, 1.0/3)
but because it divides doubles, it doesn\'t return the exact answer. For example, with 125, this g
Since it is not possible to have arbitrary-precision calculus with double
, you have three choices:
double
value is an integer or not.double
you have is a correct result.private static boolean isNthRoot(int value, int n, double precision) {
double a = Math.pow(value, 1.0 / n);
return Math.abs(a - Math.round(a)) < precision; // if a and round(a) are "close enough" then we're good
}
The problem with this approach is how to define "close enough". This is a subjective question and it depends on your requirements.
private static boolean isNthRoot(int value, int n) {
double a = Math.pow(value, 1.0 / n);
return Math.pow(Math.round(a), n) == value;
}
The advantage of this method is that there is no need to define a precision. However, we need to perform another pow
operation so this will affect performance.
There is no built-in method to calculate a double power of a BigDecimal. This question will give you insight on how to do it.
I wrote this method to compute floor(x^(1/n))
where x
is a non-negative BigInteger
and n
is a positive integer. It was a while ago now so I can't explain why it works, but I'm reasonably confident that when I wrote it I was happy that it's guaranteed to give the correct answer reasonably quickly.
To see if x
is an exact n-th
power you can check if the result raised to the power n
gives you exactly x
back again.
public static BigInteger floorOfNthRoot(BigInteger x, int n) {
int sign = x.signum();
if (n <= 0 || (sign < 0))
throw new IllegalArgumentException();
if (sign == 0)
return BigInteger.ZERO;
if (n == 1)
return x;
BigInteger a;
BigInteger bigN = BigInteger.valueOf(n);
BigInteger bigNMinusOne = BigInteger.valueOf(n - 1);
BigInteger b = BigInteger.ZERO.setBit(1 + x.bitLength() / n);
do {
a = b;
b = a.multiply(bigNMinusOne).add(x.divide(a.pow(n - 1))).divide(bigN);
} while (b.compareTo(a) == -1);
return a;
}
To use it:
System.out.println(floorOfNthRoot(new BigInteger("125"), 3));
Edit Having read the comments above I now remember that this is the Newton-Raphson method for n-th roots. The Newton-Raphson method has quadratic convergence (which in everyday language means it's fast). You can try it on numbers which have dozens of digits and you should get the answer in a fraction of a second.
You can adapt the method to work with other number types, but double
and BigDecimal
are in my view not suited for this kind of thing.
I'd go for implementing my own function to do this, possibly based on this method.