BigDecimalMath { public static BigDecimal sqrt(BigDecimal x, MathContext mathContext) { checkMathContext(mathContext); switch (x.signum()) { case 0: return ZERO; case -1: throw new ArithmeticException("Illegal sqrt(x) for x < 0: x = " + x); } int maxPrecision = mathContext.getPrecision() + 6; BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); BigDecimal result; int adaptivePrecision; if (isDoubleValue(x)) { result = BigDecimal.valueOf(Math.sqrt(x.doubleValue())); adaptivePrecision = EXPECTED_INITIAL_PRECISION; } else { result = x.multiply(ONE_HALF, mathContext); adaptivePrecision = 1; } BigDecimal last; if (adaptivePrecision < maxPrecision) { if (result.multiply(result).compareTo(x) == 0) { return round(result, mathContext); } do { last = result; adaptivePrecision <<= 1; if (adaptivePrecision > maxPrecision) { adaptivePrecision = maxPrecision; } MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); result = x.divide(result, mc).add(last).multiply(ONE_HALF, mc); } while (adaptivePrecision < maxPrecision || result.subtract(last).abs().compareTo(acceptableError) > 0); } return round(result, mathContext); } private  BigDecimalMath(); static BigDecimal toBigDecimal(String string); static BigDecimal toBigDecimal(String string, MathContext mathContext); static boolean isIntValue(BigDecimal value); static boolean isLongValue(BigDecimal value); static boolean isDoubleValue(BigDecimal value); static BigDecimal mantissa(BigDecimal value); static int exponent(BigDecimal value); static int significantDigits(BigDecimal value); static BigDecimal integralPart(BigDecimal value); static BigDecimal fractionalPart(BigDecimal value); static BigDecimal round(BigDecimal value, MathContext mathContext); static BigDecimal roundWithTrailingZeroes(BigDecimal value, MathContext mathContext); static BigDecimal reciprocal(BigDecimal x, MathContext mathContext); static BigDecimal factorial(int n); static BigDecimal factorial(BigDecimal x, MathContext mathContext); static BigDecimal gamma(BigDecimal x, MathContext mathContext); static BigDecimal bernoulli(int n, MathContext mathContext); static BigDecimal pow(BigDecimal x, BigDecimal y, MathContext mathContext); static BigDecimal pow(BigDecimal x, long y, MathContext mathContext); static BigDecimal sqrt(BigDecimal x, MathContext mathContext); static BigDecimal root(BigDecimal x, BigDecimal n, MathContext mathContext); static BigDecimal log(BigDecimal x, MathContext mathContext); static BigDecimal log2(BigDecimal x, MathContext mathContext); static BigDecimal log10(BigDecimal x, MathContext mathContext); static BigDecimal pi(MathContext mathContext); static BigDecimal e(MathContext mathContext); static BigDecimal exp(BigDecimal x, MathContext mathContext); static BigDecimal sin(BigDecimal x, MathContext mathContext); static BigDecimal asin(BigDecimal x, MathContext mathContext); static BigDecimal cos(BigDecimal x, MathContext mathContext); static BigDecimal acos(BigDecimal x, MathContext mathContext); static BigDecimal tan(BigDecimal x, MathContext mathContext); static BigDecimal atan(BigDecimal x, MathContext mathContext); static BigDecimal atan2(BigDecimal y, BigDecimal x, MathContext mathContext); static BigDecimal cot(BigDecimal x, MathContext mathContext); static BigDecimal acot(BigDecimal x, MathContext mathContext); static BigDecimal sinh(BigDecimal x, MathContext mathContext); static BigDecimal cosh(BigDecimal x, MathContext mathContext); static BigDecimal tanh(BigDecimal x, MathContext mathContext); static BigDecimal coth(BigDecimal x, MathContext mathContext); static BigDecimal asinh(BigDecimal x, MathContext mathContext); static BigDecimal acosh(BigDecimal x, MathContext mathContext); static BigDecimal atanh(BigDecimal x, MathContext mathContext); static BigDecimal acoth(BigDecimal x, MathContext mathContext);  }
@Test public void testSqrt() { for(double value : new double[] { 0, 0.1, 2, 4, 10, 16, 33.3333 }) { assertBigDecimal( "sqrt(" + value + ")", toCheck(Math.sqrt(value)), BigDecimalMath.sqrt(BigDecimal.valueOf(value), MC), MC_CHECK_DOUBLE); } }
@Test(expected = UnsupportedOperationException.class) public void testSqrtUnlimitedFail() { BigDecimalMath.sqrt(BigDecimal.valueOf(2), MathContext.UNLIMITED); }
@Test public void testSqrtRandom() { assertRandomCalculation( adaptCount(1000), "sqrt", random -> random.nextDouble() * 100 + 0.000001, Math::sqrt, (x, mathContext) -> BigDecimalMath.sqrt(x, mathContext)); }
@Test(expected = ArithmeticException.class) public void testSqrtNegative() { BigDecimalMath.sqrt(new BigDecimal(-1), MC); }