Java BigDecimal Power pow(BigDecimal base, BigDecimal power)

Here you can find the source of pow(BigDecimal base, BigDecimal power)

Description

Raises the base to the power and returns the result.

License

Apache License

Parameter

Parameter Description
BigDecimal power the power

Return

the result

Declaration

static public BigDecimal pow(BigDecimal base, BigDecimal power) 

Method Source Code

//package com.java2s;
/**/* w w  w  .j av  a  2 s.c o  m*/
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;

public class Main {
    /** 
    * Raises the base to the power and returns the result. Calculates the power
    * by finding the natural log using a Taylor sequence and exp using Newton's
    * method of approximating the nth root.
    * @param    BigDecimal base    the base
    * @param    BigDecimal power   the power
    * @return            the result
     */
    static public BigDecimal pow(BigDecimal base, BigDecimal power) {

        int precisionBase = base.precision();
        int precisionPower = power.precision();
        int precision = precisionBase < precisionPower ? precisionBase : precisionPower;

        MathContext context = new MathContext(precision, RoundingMode.HALF_DOWN);

        return pow(base, power, context);
    }

    /** 
     * Raises the base to the power and returns the result. Calculates the power
    * by finding the natural log using a Taylor sequence and exp using Newton's
    * method of approximating the nth root.
     * @param    BigDecimal     the base
     * @param    BigDecimal     the power
     * @param    MathContext    the math context
     * @return                  the result
     */
    static public BigDecimal pow(BigDecimal base, BigDecimal power, MathContext context) {

        if (base.compareTo(BigDecimal.ZERO) < 0) {
            throw new ArithmeticException("Base cannot be negative.");
        }

        if (base.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal result = ln(base);
        result = power.multiply(result, context);
        result = exp(result, context);

        return result;
    }

    /**
     * Calculates the natural logarithm using a Taylor sequqnce.
     * @param    BigDecimal    the input big decimal > 0
     * @return                 the natural logarithm
     */
    public static BigDecimal ln(BigDecimal input) {

        int precision = input.precision();
        MathContext context = new MathContext(precision, RoundingMode.HALF_DOWN);

        return ln(input, context);
    }

    /**
     * Calculates the natural logarithm using a Taylor sequqnce.
     * @param    BigDecimal    the input big decimal > 0
     * @return                 the natural logarithm
     */
    public static BigDecimal ln(BigDecimal input, MathContext context) {

        BigDecimal two = new BigDecimal("2", context);

        BigDecimal inputMinus = input.subtract(BigDecimal.ONE, context);
        BigDecimal inputPlus = input.add(BigDecimal.ONE, context);
        BigDecimal y = inputMinus.divide(inputPlus, context);

        BigDecimal result = new BigDecimal("0", context);
        BigDecimal last = new BigDecimal(result.toString(), context);

        int k = 0;
        while (true) {

            BigDecimal argumentOne = BigDecimal.ONE
                    .divide(BigDecimal.ONE.add(two.multiply(new BigDecimal(k), context), context), context);
            BigDecimal argumentTwo = y.pow(k * 2, context);
            result = result.add(argumentOne.multiply(argumentTwo, context), context);

            if (last.equals(result)) {
                break;
            }

            last = new BigDecimal(result.toString(), context);
            k++;
        }

        return y.multiply(two, context).multiply(result, context);
    }

    /**
     * Raises e to the power of the input big decimal.
     * @param    BigDecimal    the input power
     * @return                 the result
     */
    public static BigDecimal exp(BigDecimal power) {

        int precision = power.precision();

        MathContext context = new MathContext(precision, RoundingMode.HALF_DOWN);

        return exp(power, context);
    }

    /**
     * Returns e raised to the input power using a Taylor expansion with
     * @param    BigDecimal     the power
     * @param    MathContext    the math context
     * @return                  e raised to the input power
     */
    public static BigDecimal exp(BigDecimal input, MathContext context) {

        int taylorTerms = 8;

        if (input.compareTo(BigDecimal.ZERO) < 0) {

            BigDecimal inverse = exp(input.negate(), context);
            return BigDecimal.ONE.divide(inverse, context);

        } else if (input.compareTo(BigDecimal.ZERO) == 0) {

            return BigDecimal.ONE.setScale(context.getPrecision(), RoundingMode.HALF_DOWN);

        } else {

            double inputDouble = input.doubleValue();
            double inputUlpDouble = input.ulp().doubleValue();
            double taylorNumberCheck1 = Math.pow(inputDouble, taylorTerms);
            double taylorNumberCheck2 = taylorTerms * (taylorTerms - 1.0) * (taylorTerms - 2.0) * inputUlpDouble;

            if (taylorNumberCheck1 < taylorNumberCheck2) {

                BigDecimal result = BigDecimal.ONE;
                BigDecimal inputPowerNum = BigDecimal.ONE;
                BigInteger factorialNum = BigInteger.ONE;

                int taylorPrecision = 1 + (int) (Math.log10(Math.abs(0.5 / (inputUlpDouble / taylorTerms))));
                MathContext taylorContext = new MathContext(taylorPrecision);

                for (int i = 1; i <= taylorTerms; i++) {

                    factorialNum = factorialNum.multiply(new BigInteger(i + ""));
                    inputPowerNum = inputPowerNum.multiply(input);

                    BigDecimal c = inputPowerNum.divide(new BigDecimal(factorialNum), taylorContext);
                    result = result.add(c);

                    double taylorNumberCheck3 = Math.abs(inputPowerNum.doubleValue());
                    double taylorNumberCheck4 = Math.abs(c.doubleValue());
                    double taylorNumberCheck5 = inputUlpDouble / 2;

                    if (taylorNumberCheck3 < i && taylorNumberCheck4 < taylorNumberCheck5) {
                        break;
                    }
                }

                int finalPrecision = 1 + (int) (Math.log10(Math.abs(0.5 / (inputUlpDouble / 2.0))));
                ;
                MathContext finalContext = new MathContext(finalPrecision);

                return result.round(finalContext);

            } else {

                double taylorProduct = taylorTerms * (taylorTerms - 1.0) * (taylorTerms - 2.0) * inputUlpDouble;
                double taylorPower = Math.pow(inputDouble, taylorTerms);

                Double scaleBy10Double = 1.0 - Math.log10(taylorProduct / taylorPower) / (taylorTerms - 1.0);
                int scaleBy10 = scaleBy10Double.intValue();

                BigDecimal inputRaised10 = input.scaleByPowerOfTen(-scaleBy10);
                BigDecimal expxby10 = exp(inputRaised10, context);

                MathContext contextRaised10 = new MathContext(expxby10.precision() - scaleBy10);

                while (scaleBy10 > 0) {

                    int minimum = Math.min(8, scaleBy10);
                    scaleBy10 -= minimum;

                    MathContext minContext = new MathContext(expxby10.precision() - minimum + 2);
                    int precisionMin = 1;

                    while (minimum-- > 0) {
                        precisionMin *= 10;
                    }

                    expxby10 = expxby10.pow(precisionMin, minContext);

                }

                return expxby10.round(contextRaised10);
            }
        }
    }
}

Related

  1. decimalPow(BigDecimal number, BigDecimal power)
  2. pow(BigDecimal arg0, BigDecimal arg1)
  3. pow(BigDecimal b, int p, int q)
  4. pow(BigDecimal base, BigDecimal exponent)
  5. pow(BigDecimal one, int another)
  6. pow(BigDecimal savedValue, BigDecimal value)
  7. power(BigDecimal base, int exponent)
  8. power(final BigDecimal value, final long power)