JDK-8165814 : Sqrt of a BigDecimal
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.math
  • Affected Version: 8,9
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2016-09-11
  • Updated: 2016-09-12
  • Resolved: 2016-09-12
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
I have often needed the square root of a positive BigDecimal, and each time I have rolled my own.  Today, I came across a really nice algorithm, and a new algorithm I had not seen before.  Both are from the Wikipedia article "Newton-Raphson Method."  I hope you can include something like them in BigDecimal.  We also need a Log to base b routine in BigDecimal, for which I don't have a good solution yet.  The Halley''s routine exhibits cubic convergence, while Newton-Raphson is only quadratic.  The text case shows no difference between the two, but the difference exists as seen in other problems.

JUSTIFICATION :
Square root arises all them time and in many algorithms.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The ability to take the square root of a positive BigDecimal.
ACTUAL -
User must write his or her own.

---------- BEGIN SOURCE ----------
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package testbdsqrt;

import java.math.BigDecimal;
import static java.math.BigDecimal.ONE;
import static java.math.BigDecimal.ZERO;
import java.math.MathContext;
import java.util.ArrayList;

/**
 *
 * @author CElliott
 */
public class TestBDSqrt {
  private static final BigDecimal TWO = ONE.add(ONE);
  private static final BigDecimal THREE = TWO.add(ONE);
  private static final MathContext mc = new MathContext(66);
  

  
  public static BigDecimal NewtonRaphsonSqrt( BigDecimal n, double tolerance, MathContext mc ) throws IllegalArgumentException{
    if( n.compareTo(ZERO) < 0 )
      throw new IllegalArgumentException("Aruments to NewtonRaphsonSqrt must be positive.");
    ArrayList<BigDecimal> results = new ArrayList<>();
    BigDecimal xnp1 = new BigDecimal(Math.sqrt(n.doubleValue()), mc);
    results.add(xnp1);
    xnp1 = xnp1.add(n.divide(xnp1, mc)).divide(TWO, mc);
    //System.out.printf("%30.25f%n", xnp1);
    while(true){
      if(xnp1.subtract(results.get(results.size()-1), mc).abs(mc).doubleValue()<=tolerance)
        break;
      results.add(xnp1);
      xnp1 = xnp1.add(n.divide(xnp1, mc)).divide(TWO, mc);
      //System.out.printf("%30.25f%n", xnp1);
    }
    results.add(xnp1);
    return results.get(results.size()-1);
  }
  
  public static BigDecimal HalleysSqrt( BigDecimal n, double tolerance, MathContext mc ) throws IllegalArgumentException{
    if( n.compareTo(ZERO) < 0 )
      throw new IllegalArgumentException("Aruments to HalleysSqrt must be positive.");
    ArrayList<BigDecimal> results = new ArrayList<>();
    BigDecimal xnp1 = new BigDecimal(Math.sqrt(n.doubleValue()), mc);
    results.add(xnp1);
    xnp1 = THREE.multiply(n, mc).add(xnp1.pow(2,mc), mc).divide(n.divide(xnp1, mc).add(THREE.multiply(xnp1, mc)), mc);
    //System.out.printf("%30.25f%n", xnp1);
    while(true){
      if(xnp1.subtract(results.get(results.size()-1), mc).abs(mc).doubleValue()<=tolerance)
        break;
      results.add(xnp1);
      xnp1 = THREE.multiply(n, mc).add(xnp1.pow(2,mc), mc).divide(n.divide(xnp1,mc).add(THREE.multiply(xnp1, mc)), mc);
      //System.out.printf("%30.25f%n", xnp1);
    }
    results.add(xnp1);
    return results.get(results.size()-1);
  }
  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    BigDecimal arg = new BigDecimal(Long.MAX_VALUE);
    arg = arg.pow(2).add(new BigDecimal("0.12345678987654321"));
    BigDecimal results = NewtonRaphsonSqrt(arg, 0.0000000000000001, mc);
    System.out.println();
    System.out.printf("The Newton-Raphson Sqrt of %f is %30.25f, whose square is %30.25f%n", arg, results, results.pow(2));
  
    results = HalleysSqrt(arg, 0.0000000000000001, mc);
    System.out.println();
    System.out.printf("The Halley's Sqrt of %f is %30.25f, whose square is %30.25f%n", arg, results, results.pow(2)); 
 }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package testbdsqrt;

import java.math.BigDecimal;
import static java.math.BigDecimal.ONE;
import static java.math.BigDecimal.ZERO;
import java.math.MathContext;
import java.util.ArrayList;

/**
 *
 * @author CElliott
 */
public class TestBDSqrt {
  private static final BigDecimal TWO = ONE.add(ONE);
  private static final BigDecimal THREE = TWO.add(ONE);
  private static final MathContext mc = new MathContext(66);
  

  
  public static BigDecimal NewtonRaphsonSqrt( BigDecimal n, double tolerance, MathContext mc ) throws IllegalArgumentException{
    if( n.compareTo(ZERO) < 0 )
      throw new IllegalArgumentException("Aruments to NewtonRaphsonSqrt must be positive.");
    ArrayList<BigDecimal> results = new ArrayList<>();
    BigDecimal xnp1 = new BigDecimal(Math.sqrt(n.doubleValue()), mc);
    results.add(xnp1);
    xnp1 = xnp1.add(n.divide(xnp1, mc)).divide(TWO, mc);
    //System.out.printf("%30.25f%n", xnp1);
    while(true){
      if(xnp1.subtract(results.get(results.size()-1), mc).abs(mc).doubleValue()<=tolerance)
        break;
      results.add(xnp1);
      xnp1 = xnp1.add(n.divide(xnp1, mc)).divide(TWO, mc);
      //System.out.printf("%30.25f%n", xnp1);
    }
    results.add(xnp1);
    return results.get(results.size()-1);
  }
  
  public static BigDecimal HalleysSqrt( BigDecimal n, double tolerance, MathContext mc ) throws IllegalArgumentException{
    if( n.compareTo(ZERO) < 0 )
      throw new IllegalArgumentException("Aruments to HalleysSqrt must be positive.");
    ArrayList<BigDecimal> results = new ArrayList<>();
    BigDecimal xnp1 = new BigDecimal(Math.sqrt(n.doubleValue()), mc);
    results.add(xnp1);
    xnp1 = THREE.multiply(n, mc).add(xnp1.pow(2,mc), mc).divide(n.divide(xnp1, mc).add(THREE.multiply(xnp1, mc)), mc);
    //System.out.printf("%30.25f%n", xnp1);
    while(true){
      if(xnp1.subtract(results.get(results.size()-1), mc).abs(mc).doubleValue()<=tolerance)
        break;
      results.add(xnp1);
      xnp1 = THREE.multiply(n, mc).add(xnp1.pow(2,mc), mc).divide(n.divide(xnp1,mc).add(THREE.multiply(xnp1, mc)), mc);
      //System.out.printf("%30.25f%n", xnp1);
    }
    results.add(xnp1);
    return results.get(results.size()-1);
  }
  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    BigDecimal arg = new BigDecimal(Long.MAX_VALUE);
    arg = arg.pow(2).add(new BigDecimal("0.12345678987654321"));
    BigDecimal results = NewtonRaphsonSqrt(arg, 0.0000000000000001, mc);
    System.out.println();
    System.out.printf("The Newton-Raphson Sqrt of %f is %30.25f, whose square is %30.25f%n", arg, results, results.pow(2));
  
    results = HalleysSqrt(arg, 0.0000000000000001, mc);
    System.out.println();
    System.out.printf("The Halley's Sqrt of %f is %30.25f, whose square is %30.25f%n", arg, results, results.pow(2)); 
 }
}



Comments
A BigDecimal.sqrt method was added under JDK-4851777 and has been available since JDK 9 b120. Closing as a duplicate.
12-09-2016