Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Square root of BigDecimal in Java

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?

like image 281
user1853200 Avatar asked Nov 30 '12 17:11

user1853200


People also ask

What is MathContext in Java?

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.

What is the BigDecimal in Java?

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.

Can you add BigDecimal in Java?

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.


2 Answers

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.

like image 55
haventchecked Avatar answered Sep 22 '22 19:09

haventchecked


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!

like image 35
barwnikk Avatar answered Sep 22 '22 19:09

barwnikk