Introduction
Recently, I encountered a lack of precision in a math problem. Most of the people don't know that using
float
or
double
is not as good as we think that it is. So after Googling my problem, I found that I could use
BigDecimal
class to solve the problem.
BigDecimal
is used in programs that deal with currency problems. So add and subtraction are very well implemented.
So I decided to use BigDecimal
and even though it's kind of annoying to replace the classic operands with "add." , "subtraction", etc. everything was doing OK. Until I need to replace the Square Root! Where is the Square Root?
Well, BigDecimal
doesn't implement Square Root so I decided to implement my own method. I remember back in college that we used to calculate squareRoot using "Newton Raphson Method". This method uses a Mathematics Sequence to find out the square root.
Using the Code
I will only code a
static
method that could be used to create a new Class to replace
BigDecimal
.
It may surprise you that a simple division like "1/3" will throw an exception. BigDecimal
likes to be precised and "0.3333...." is not! So you will have to define the precision in any division. I will use two constans "SQRT_DIG" & "SQRT_PRE" to define how many digits I want.
private static final BigDecimal SQRT_DIG = new BigDecimal(150);
private static final BigDecimal SQRT_PRE = new BigDecimal(10).pow(SQRT_DIG.intValue());
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);
}
public static BigDecimal bigSqrt(BigDecimal c)
{
return sqrtNewtonRaphson(c,new BigDecimal(1),new BigDecimal(1).divide(SQRT_PRE));
}
The method to get any Square Root is
bigSqrt
. As you can see,
sqrtNewtonRaphson
will call itself until it gets the precision that you want.