Can we compute the square root of a BigDecimal
in Java by using only the Java API and not a custom-made 100-line algorithm?
The java. math. MathContext class provides immutable objects which encapsulate the context settings and describes certain rules for numerical operators, such as those implemented by the BigDecimal class.
A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale.
add(BigDecimal val) is used to calculate the Arithmetic sum of two BigDecimals. This method is used to find arithmetic addition of large numbers of range much greater than the range of largest data type double of Java without compromising with the precision of the result.
I've used this and it works quite well. Here's an example of how the algorithm works at a high level.
Edit: I was curious to see just how accurate this was as defined below. Here is the sqrt(2) from an official source:
(first 200 digits) 1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206057147
and here it is using the approach I outline below with SQRT_DIG
equal to 150:
(first 200 digits) 1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206086685
The first deviation occurs after 195 digits of precision. Use at your own risk if you need such a high level of precision as this.
Changing SQRT_DIG
to 1000 yielded 1570 digits of precision.
private static final BigDecimal SQRT_DIG = new BigDecimal(150); private static final BigDecimal SQRT_PRE = new BigDecimal(10).pow(SQRT_DIG.intValue()); /** * Private utility method used to compute the square root of a BigDecimal. * * @author Luciano Culacciatti * @url http://www.codeproject.com/Tips/257031/Implementing-SqrtRoot-in-BigDecimal */ private static BigDecimal sqrtNewtonRaphson (BigDecimal c, BigDecimal xn, BigDecimal precision){ BigDecimal fx = xn.pow(2).add(c.negate()); BigDecimal fpx = xn.multiply(new BigDecimal(2)); BigDecimal xn1 = fx.divide(fpx,2*SQRT_DIG.intValue(),RoundingMode.HALF_DOWN); xn1 = xn.add(xn1.negate()); BigDecimal currentSquare = xn1.pow(2); BigDecimal currentPrecision = currentSquare.subtract(c); currentPrecision = currentPrecision.abs(); if (currentPrecision.compareTo(precision) <= -1){ return xn1; } return sqrtNewtonRaphson(c, xn1, precision); } /** * Uses Newton Raphson to compute the square root of a BigDecimal. * * @author Luciano Culacciatti * @url http://www.codeproject.com/Tips/257031/Implementing-SqrtRoot-in-BigDecimal */ public static BigDecimal bigSqrt(BigDecimal c){ return sqrtNewtonRaphson(c,new BigDecimal(1),new BigDecimal(1).divide(SQRT_PRE)); }
be sure to check out barwnikk's answer. it's more concise and seemingly offers as good or better precision.
public static BigDecimal sqrt(BigDecimal A, final int SCALE) { BigDecimal x0 = new BigDecimal("0"); BigDecimal x1 = new BigDecimal(Math.sqrt(A.doubleValue())); while (!x0.equals(x1)) { x0 = x1; x1 = A.divide(x0, SCALE, ROUND_HALF_UP); x1 = x1.add(x0); x1 = x1.divide(TWO, SCALE, ROUND_HALF_UP); } return x1; }
This work perfect! Very fast for more than 65536 digits!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With