Search code examples
javabigdecimal

Computing the nth root of p using BigDecimals


I am currently trying to solve this problem as described here:

http://uva.onlinejudge.org/external/1/113.pdf

The plan was to implement a recursive function to derive the solution. Some of the code here comes from Rosetta code for determining the nth root.

// Power of Cryptography 113

import java.util.Scanner;
import java.math.BigDecimal;
import java.math.RoundingMode;

// k can be 10^9 
// n <= 200
// p <= 10^101

class crypto { 
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()) {
            // Given two integers (n,p)
            // Find k such k^n = p
            int n = in.nextInt();
            BigDecimal p = in.nextBigDecimal();
            System.out.println(nthroot(n,p));
        }
    }

    public static BigDecimal nthroot(int n, BigDecimal A) {
        return nthroot(n, A, .001);
    }

    public static BigDecimal nthroot(int n, BigDecimal A, double p) {
        if(A.compareTo(BigDecimal.ZERO) < 0) return new BigDecimal(-1);
        // we handle only real positive numbers
        else if(A.equals(BigDecimal.ZERO)) {
            return BigDecimal.ZERO;
        }
        BigDecimal x_prev = A;
        BigDecimal x = A.divide(new BigDecimal(n));  // starting "guessed" value...
        BigDecimal y = x.subtract(x_prev);

        while(y.abs().compareTo(new BigDecimal(p)) > 0) {
            x_prev = x;
            BigDecimal temp = new BigDecimal(n-1.0);
            x = (x.multiply(temp).add(A).divide(x.pow(temp.intValue())).divide(new BigDecimal(n)));
        }
        return x;
    }
}

And here is the resulting error code:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1616)
at crypto.nthroot(crypto.java:38)
at crypto.nthroot(crypto.java:24)
at crypto.main(crypto.java:19)

Solution

  • That is expected if the resulting mathematical decimal number is non-terminating. The Javadocs for the 1-arg overload of divide state:

    Throws:

    ArithmeticException - if the exact quotient does not have a terminating decimal expansion

    Use another overload of the divide method to specify a scale (a cutoff) (and a RoundingMode).