BigDecimalMath { public static BigDecimal pow(BigDecimal x, BigDecimal y, MathContext mathContext) { checkMathContext(mathContext); if (x.signum() == 0) { switch (y.signum()) { case 0 : return round(ONE, mathContext); case 1 : return round(ZERO, mathContext); } } try { long longValue = y.longValueExact(); return pow(x, longValue, mathContext); } catch (ArithmeticException ex) { } if (fractionalPart(y).signum() == 0) { return powInteger(x, y, mathContext); } MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = exp(y.multiply(log(x, mc), mc), mc); 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 testPow2Random() { assertRandomCalculation( adaptCount(1000), "x*x", "pow(x,2)", (random, mathContext) -> randomBigDecimal(random, mathContext), (x, mathContext) -> x.multiply(x, mathContext), (x, mathContext) -> BigDecimalMath.pow(x, 2, mathContext)); }
@Test(expected = ArithmeticException.class) public void testPowIntZeroPowerNegative() { BigDecimalMath.pow(BigDecimal.valueOf(0), -5, MC); }
@Test public void testPowIntUnlimited() { assertEquals(BigDecimal.valueOf(1.44), BigDecimalMath.pow(BigDecimal.valueOf(1.2), 2, MathContext.UNLIMITED)); assertEquals(BigDecimal.valueOf(0.25), BigDecimalMath.pow(BigDecimal.valueOf(2), -2, MathContext.UNLIMITED)); }
@Test(expected = ArithmeticException.class) public void testPowIntUnnecessaryFail() { BigDecimalMath.pow(BigDecimal.valueOf(1.2), 4, new MathContext(3, RoundingMode.UNNECESSARY)); }
@Test(expected = ArithmeticException.class) public void testPowIntUnlimitedFail() { BigDecimalMath.pow(BigDecimal.valueOf(1.2), -2, MathContext.UNLIMITED); }
@Test(expected = ArithmeticException.class) public void testPowInt0NegativeY() { System.out.println(BigDecimalMath.pow(BigDecimal.valueOf(0), -5, MC)); }
@Test public void testPowPositiveX() { for(double x : new double[] { 1, 1.5, 2, 2.5, 3, 4, 5 }) { for(double y : new double[] { -5, -4, -3, -2.5, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 4, 5 }) { assertBigDecimal( x + "^" + y, toCheck(Math.pow(x, y)), BigDecimalMath.pow(BigDecimal.valueOf(x), BigDecimal.valueOf(y), MC), MC_CHECK_DOUBLE); } } for(double x : new double[] { 0 }) { for(double y : new double[] { 0, 0.5, 1, 1.5, 2, 2.5, 3, 4, 5 }) { assertBigDecimal( x + "^" + y, toCheck(Math.pow(x, y)), BigDecimalMath.pow(BigDecimal.valueOf(x), BigDecimal.valueOf(y), MC), MC_CHECK_DOUBLE); } } }
@Test public void testPowNegativeX() { for(double x : new double[] { -2, -1 }) { for(double y : new double[] { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }) { assertBigDecimal( x + "^" + y, toCheck(Math.pow(x, y)), BigDecimalMath.pow(BigDecimal.valueOf(x), BigDecimal.valueOf(y), MC), MC); } } }
@Test(expected = ArithmeticException.class) public void testPow0NegativeY() { System.out.println(BigDecimalMath.pow(BigDecimal.valueOf(0), BigDecimal.valueOf(-5), MC)); }
@Test public void testPowLargeInt() { BigDecimal x = new BigDecimal("1.5"); BigDecimal y = new BigDecimal("1E10"); BigDecimal expected = new BigDecimal("3.60422936590014149127041615892759056162677175765E1760912590"); assertEquals(10_000_000_000L, y.longValueExact()); assertPrecisionCalculation( expected, mathContext -> { return BigDecimalMath.pow(x, y, mathContext); }, 20); }
@Test public void testPowVeryLargeInt() { BigDecimal x = new BigDecimal("1.00000000000001"); BigDecimal y = new BigDecimal("1E20"); BigDecimal expected = new BigDecimal("3.03321538163601059899125791999959844544825181205425E434294"); assertPrecisionCalculation( expected, mathContext -> { return BigDecimalMath.pow(x, y, mathContext); }, 20); }
@Test public void testPowRandom() { assertRandomCalculation( adaptCount(1000), "pow", random -> random.nextDouble() * 100 + 0.000001, random -> random.nextDouble() * 100 - 50, Math::pow, (x, y, mathContext) -> BigDecimalMath.pow(x, y, mathContext)); }
@Test(expected = ArithmeticException.class) public void testPowOverflow() { BigDecimalMath.pow(new BigDecimal("123"), new BigDecimal("1E20"), MC); }
@Test(expected = UnsupportedOperationException.class) public void testPowUnlimitedFail() { BigDecimalMath.pow(BigDecimal.valueOf(1.2), BigDecimal.valueOf(1.1), MathContext.UNLIMITED); }