BigDecimal iteration2;
BigDecimal temp1 = null;
BigDecimal temp2 = null; // temp values
int extraPrecision = number.precision();
MathContext mc = new MathContext(extraPrecision, RoundingMode.HALF_UP);
numberToBeSquareRooted = number; // bd global variable
double num = numberToBeSquareRooted.doubleValue(); // bd to double
if (mc.getPrecision() == 0)
throw new IllegalArgumentException("\nRoots need a MathContext precision > 0");
if (num < 0.)
throw new ArithmeticException("\nCannot calculate the square root of a negative number");
if (num == 0.)
return number.round(mc); // return sqrt(0) immediately
if (mc.getPrecision() < 50) // small precision is buggy..
extraPrecision += 10; // ..make more precise
int startPrecision = 1; // default first precision
/* create the initial values for the iteration procedure:
* x0: x ~ sqrt(d)
* v0: v = 1/(2*x)
*/
if (num == Double.POSITIVE_INFINITY) // d > 1.7E308
{
BigInteger bi = numberToBeSquareRooted.unscaledValue();
int biLen = bi.bitLength();
int biSqrtLen = biLen / 2; // floors it too
bi = bi.shiftRight(biSqrtLen); // bad guess sqrt(d)
iteration1 = new BigDecimal(bi); // x ~ sqrt(d)
MathContext mm = new MathContext(5, RoundingMode.HALF_DOWN); // minimal precision
extraPrecision += 10; // make up for it later
iteration2 = BigDecimal.ONE.divide(TWO.multiply(iteration1, mm), mm); // v = 1/(2*x)
}
else // d < 1.7E10^308 (the usual numbers)
{
double s = Math.sqrt(num);
iteration1 = new BigDecimal(((Double) s).toString()); // x = sqrt(d)
iteration2 = new BigDecimal(((Double) (1. / 2. / s)).toString()); // v = 1/2/x
// works because Double.MIN_VALUE * Double.MAX_VALUE ~ 9E-16, so: v > 0
startPrecision = 64;
}
digits = mc.getPrecision() + extraPrecision; // global limit for procedure
// create initial MathContext(precision, RoundingMode)
MathContext n = new MathContext(startPrecision, mc.getRoundingMode());
return sqrtProcedure(n, digits, numberToBeSquareRooted, iteration1, iteration2, temp1, temp2); // return square root using argument precision
}