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));
}
}