8

I have a simple BigDecimal that I want to power to another BigDecimal, for example 11.11^-1.54. What would be the neatest way to do it in Java/Android? I don't like the idea of converting to doubles because it is for a medical application, so I would appreciate the biggest presicion possible. So far I have reviewed http://commons.apache.org/math/ and math stuff from Google Guava, but found nothing.

Edit: The whole calculation is complex, and has many operations like this. I need as much precision at the end as possible.

Elchin
  • 584
  • 6
  • 19
  • Partially duplicated by [this question](http://stackoverflow.com/questions/16441769/javas-bigdecimal-powerbigdecimal-exponent-is-there-a-java-library-that-does) – Geoffrey De Smet Mar 21 '14 at 11:29

4 Answers4

9

A utility class for BigDecimal https://github.com/tareknaj/BigFunctions

Example for z = x^y --> z = exp ( ln(x) * y )

final int SCALE = 10;
BigDecimal x = new BigDecimal(1);
BigDecimal y = new BigDecimal(12);

BigDecimal z = BigFunctions.exp( BigFunctions.ln(x, SCALE).multiply(y),SCALE );
  • What's the license? Apache license by any chance? – Geoffrey De Smet Jun 23 '14 at 09:19
  • Any plans to add that method to Apache's commons-lang's [NumberUtils](http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/math/NumberUtils.html) or Google's guava? – Geoffrey De Smet Jun 23 '14 at 09:21
  • @GeoffreyDeSmet No License, it's just a utility class – softawareblog.com Jul 04 '14 at 13:02
  • No license implies it's proprietary and illegal to reuse or distribute... Just apply Apache Software License, MIT or BSD, which impose virtually no restrictions on usage. – Geoffrey De Smet Jul 05 '14 at 07:56
  • 1
    This class uses `Thread.yield();` while doing computations, which is a _very_ strange thing to have inside a mathematical function. – Roman Jun 11 '16 at 10:14
  • @softawareblog.com This is great! To make consumption of this code easier, it needs to get into Maven Central, which is a lot of red tape that can be avoided by [adding this code to commons-lang's NumberUtils, which we would like to do](http://stackoverflow.com/a/41763229/472109) (and the license allows us to do so). As part of commons-lang, it will be very easy to consume, on maven central, peer reviewed and visible to the entire community. We 'll keep the author tags of course to give you credit. – Geoffrey De Smet Jan 20 '17 at 12:08
4

How many digits of precision do you need? You are only using 4 digits in your example. If this is medical and there for real world, you can only measure most things in the real world to 10-13 digits of accuracy and double has up to 16 digits of accuracy.

System.out.println(Math.pow(11.11, -1.54));

prints

0.024524510581710988

If you use a library from this book http://www.apropos-logic.com/nc/, you can get

int runs = 10000;

long start = System.nanoTime();
double x1 = 0;
for (int i = 0; i < runs; i++)
    x1 = Math.pow(11.11, -1.54);
long time = System.nanoTime() - start;
System.out.println(x1 + " took " + time / runs / 1e3 + " us avg.");

long start2 = System.nanoTime();
BigDecimal x2 = null;
for (int i = 0; i < runs; i++)
    x2 = exp(ln(BigDecimal.valueOf(11.11), 20).multiply(BigDecimal.valueOf(-1.54)), 20);
long time2 = System.nanoTime() - start2;
System.out.println(x2 + " took " + time2 / runs / 1e3 + " us avg.");

prints (us for micro-seconds)

0.024524510581710988 took 0.478 us avg.
0.02452451058171098739 took 603.769 us avg.

with 40 digits of precision

0.0245245105817109873886495555036930857940 took 1409 us avg.

which may still be fast enough on your device.

I haven't included the code, partly because its very long. I am impressed how fast it is. ;)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • As much of precision as possible. The calculation itself is complex, and has many operations as such. Is double the best way to get it? With rounding it up to the necessary precision at the end of the complex calculation. – Elchin Aug 07 '12 at 15:17
  • If you really have no idea how much precision you need and performance is not an issue, I would use BigDecimal. – Peter Lawrey Aug 07 '12 at 15:32
  • 1
    Thanks for the library link! I think I will go with double for now, however BigDecimal method is very useful! I just wonder how come Apache Commons Math did not include it. – Elchin Aug 07 '12 at 16:09
  • 1
    Link to the library is dead. Author's page for the book is [here](http://www.apropos-logic.com/nc/). – MT0 Jun 15 '17 at 08:14
4

Look into "Java Number Cruncher: The Java Programmer's Guide to Numerical Computing" - Chapter 12.5 Big Decimal Functions : there is some source code with as exact as possible algorithm to compute exponential and logarithm.

Using the mathematical formula : x^y=exp(y*ln(x)) you can achieve a result with maximum precision.

Nevertheless doubles do have a good precision and I strongly recommand you test if it's not precise enough for your need.

Laucia
  • 222
  • 2
  • 11
2

There is a good library ApFloat: http://www.apfloat.org/

bobharris
  • 173
  • 3
  • 10