29

In my little project, I need to do something like Math.pow(7777.66, 5555.44) only with VERY big numbers. I came across a few solutions:

  • Use double - but the numbers are too big
  • Use BigDecimal.pow but no support for fractional
  • Use the X^(A+B)=X^A*X^B formula (B is the remainder of the second num), but again no support for big X or big A because I still convert to double
  • Use some kind of Taylor series algorithm or something like that - I'm not very good at math so this one is my last option if I don't find any solutions (some libraries or formula for (A+B)^(C+D)).

Does anyone know of a library or an easy solution? I figured that many people deal with the same problem...

p.s. I found some library called ApFloat that claims to do it approximately, but the results I got were so approximate that even 8^2 gave me 60...

Michael
  • 1,453
  • 3
  • 20
  • 28
Eugene Marin
  • 1,706
  • 3
  • 23
  • 35
  • Could you give an example of what you try to accomplish, 8^2 != 64 sounds poor and 2^100^100 needs to be scaled down. – stacker Aug 26 '10 at 21:56
  • I must say I tried the formula trick, and it works fine so far even with numbers with millions of digits! (Looks like I don't know everything about double and int)... Examples: 50!^10! = 12.50911317862076252364259*10^233996181 50!^0.06 = 7395.788659356498101260513 The code is a little long to post here, but you get the idea of X^(A+B)=X^A*X^B... Now I'm trying to understand how and why (and if) it really works with numbers that huge. – Eugene Marin Aug 27 '10 at 22:08
  • 1
    I have already given the solution there http://stackoverflow.com/questions/11848887/bigdecimal-to-the-power-of-bigdecimal-on-java-android/22556217#22556217 – softawareblog.com Mar 21 '14 at 10:39

3 Answers3

27

The solution for arguments under 1.7976931348623157E308 (Double.MAX_VALUE) but supporting results with MILLIONS of digits:

Since double supports numbers up to MAX_VALUE (for example, 100! in double looks like this: 9.332621544394415E157), there is no problem to use BigDecimal.doubleValue(). But you shouldn't just do Math.pow(double, double) because if the result is bigger than MAX_VALUE you will just get infinity. SO: use the formula X^(A+B)=X^A*X^B to separate the calculation to TWO powers, the big, using BigDecimal.pow, and the small (remainder of the 2nd argument), using Math.pow, then multiply. X will be copied to DOUBLE - make sure it's not bigger than MAX_VALUE, A will be INT (maximum 2147483647 but the BigDecimal.pow doesn't support integers more than a billion anyway), and B will be double, always less than 1. This way you can do the following (ignore my private constants etc):

    int signOf2 = n2.signum();
    try {
        // Perform X^(A+B)=X^A*X^B (B = remainder)
        double dn1 = n1.doubleValue();
        // Compare the same row of digits according to context
        if (!CalculatorUtils.isEqual(n1, dn1))
            throw new Exception(); // Cannot convert n1 to double
        n2 = n2.multiply(new BigDecimal(signOf2)); // n2 is now positive
        BigDecimal remainderOf2 = n2.remainder(BigDecimal.ONE);
        BigDecimal n2IntPart = n2.subtract(remainderOf2);
        // Calculate big part of the power using context -
        // bigger range and performance but lower accuracy
        BigDecimal intPow = n1.pow(n2IntPart.intValueExact(),
                CalculatorConstants.DEFAULT_CONTEXT);
        BigDecimal doublePow =
            new BigDecimal(Math.pow(dn1, remainderOf2.doubleValue()));
        result = intPow.multiply(doublePow);
    } catch (Exception e) {
        if (e instanceof CalculatorException)
            throw (CalculatorException) e;
        throw new CalculatorException(
            CalculatorConstants.Errors.UNSUPPORTED_NUMBER_ +
                "power!");
    }
    // Fix negative power
    if (signOf2 == -1)
        result = BigDecimal.ONE.divide(result, CalculatorConstants.BIG_SCALE,
                RoundingMode.HALF_UP);

Results examples:

50!^10! = 12.50911317862076252364259*10^233996181

50!^0.06 = 7395.788659356498101260513
Eugene Marin
  • 1,706
  • 3
  • 23
  • 35
  • 9
    This is not useful without the `CalculatorUtils`, `CalculatorConstants`, or `CalculatorException` classes – Ky - Aug 11 '16 at 23:46
2

The big-math library released under MIT license has a simple static helper BigDecimalMath.log(BigDecimal, MathContext) for log and many other functions not included with BigDecimal. Very simple to use and has lots of benchmarking data to compare performance.

Ben Holland
  • 2,309
  • 4
  • 34
  • 50
0

Exponents = logarithms.

Take a look at Logarithm of a BigDecimal

Community
  • 1
  • 1
Matthew Flynn
  • 2,210
  • 19
  • 27
  • The source code referred to the accepted answer of this question has more solutions than just for natural log. – prunge Jan 05 '12 at 00:47
  • 1
    @Prunge - Thanks. I never actually said anything about natural log. Really, if you look at the Gene Marin's accepted answer, what he is describing is logarithmic. X^(A+B)=X^A*X^B is equivalent to saying log(base X)A + log(base X)B = log(base X)(A*B). This should allow you to bring the numbers to a manageable order of magnitude . – Matthew Flynn Jan 05 '12 at 04:56