views:

1261

answers:

15

Hi,

I need to calculate Math.exp() from java very frequently, is it possible to get a native version to run faster than java's Math.exp()??

I tried just jni + C, but it's slower than just plain java.

+5  A: 

Use Java's.

Also, cache results of the exp and then you can look up the answer faster than calculating them again.

jjnguy
+4  A: 

You'd want to wrap whatever loop's calling Math.exp() in C as well. Otherwise, the overhead of marshalling between Java and C will overwhelm any performance advantage.

John Millikin
A: 

Since the Java code will get compiled to native code with the just-in-time (JIT) compiler, there's really no reason to use JNI to call native code.

Also, you shouldn't cache the results of a method where the input parameters are floating-point real numbers. The gains obtained in time will be very much lost in amount of space used.

Alan Krueger
A: 

The problem with using JNI is the overhead involved in making the call to JNI. The Java virtual machine is pretty optimized these days, and calls to the built-in Math.exp() are automatically optimized to call straight through to the C exp() function, and they might even be optimized into straight x87 floating-point assembly instructions.

Adam Rosenfield
+2  A: 

The real question is, has this become a bottle neck for you? Have you profiled your application and found this to be a major cause of slow down?

If not, I would recommend using Java's version. Try not to pre-optimize as this will just cause development slow down. You may spend an extended amount of time on a problem that may not be a problem.

That being said, I think your test gave you your answer. If jni + C is slower, use java's version.

scubabbl
A: 

There's simply an overhead associated with using the JNI, see also: http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html

So as others have suggested try to collate operations that would involve using the JNI.

tonylo
+2  A: 

You might be able to get it to run faster if you do them in batches. Making a JNI call adds overhead, so you don't want to do it for each exp() you need to calculate. I'd try passing an array of 100 values and getting the results to see if it helps performance.

Bill the Lizard
A: 

Write your own, tailored to your needs.

For instance, if all your exponents are of the power of two, you can use bit-shifting. If you work with a limited range or set of values, you can use look-up tables. If you don't need pin-point precision, you use an imprecise, but faster, algorithm.

A: 

There is a cost associated with calling across the JNI boundary.

If you could move the loop that calls exp() into the native code as well, so that there is just one native call, then you might get better results, but I doubt it will be significantly faster than the pure Java solution.

I don't know the details of your application, but if you have a fairly limited set of possible arguments for the call, you could use a pre-computed look-up table to make your Java code faster.

Dan Dyer
A: 

how would one cache the results of Math.exp() in java for faster look up instead of recalculating? Map doesn't sound like a good idea, or is it??

Dan
A: 

There are faster algorithms for exp depending on what your'e trying to accomplish. Is the problem space restricted to a certain range, do you only need a certain resolution, precision, or accuracy, etc.

If you define your problem very well, you may find that you can use a table with interpolation, for instance, which will blow nearly any other algorithm out of the water.

What constraints can you apply to exp to gain that performance trade-off?

Adam Davis
+7  A: 

+1 to writing your own exp() implementation. That is, if this is really a bottle-neck in your application. If you can deal with a little inaccuracy, there are a number of extremely efficient exponent estimation algorithms out there, some of them dating back centuries. As I understand it, Java's exp() implementation is fairly slow, even for algorithms which must return "exact" results.

Oh, and don't be afraid to write that exp() implementation in pure-Java. JNI has a lot of overhead, and the JVM is able to optimize bytecode at runtime sometimes even beyond what C/C++ is able to achieve.

Daniel Spiewak
A: 

well, i don't need infinite precision that's for sure. I run a fitting algorithm and the minimum error of the fitting result is way larger than the precision of the Math.exp().

Dan
A: 

I run a fitting algorithm and the minimum error of the fitting result is way larger than the precision of the Math.exp().

Transcendental functions are always much more slower than addition or multiplication and a well-known bottleneck. If you know that your values are in a narrow range, you can simply build a lookup-table (Two sorted array ; one input, one output). Use Arrays.binarySearch to find the correct index and interpolate value with the elements at [index] and [index+1].

Another method is to split the number. Lets take e.g. 3.81 and split that in 3+0.81. Now you multiply e = 2.718 three times and get 20.08.

Now to 0.81. All values between 0 and 1 converge fast with the well-known exponential series

1+x+x^2/2+x^3/6+x^4/24.... etc.

Take as much terms as you need for precision; unfortunately it's slower if x approaches 1. Lets say you go to x^4, then you get 2.2445 instead of the correct 2.2448

Then multiply the result 2.781^3 = 20.08 with 2.781^0.81 = 2.2445 and you have the result 45.07 with an error of one part of two thousand (correct: 45.15).

TSK
+7  A: 

This has already been requested several times (see e.g. here). Here is an approximation to Math.exp(), copied from this blog posting:

public static double exp(double val) {
    final long tmp = (long) (1512775 * val + (1072693248 - 60801));
    return Double.longBitsToDouble(tmp << 32);
}

It is basically the same as a lookup table with 2048 entries and linear interpolation between the entries, but all this with IEEE floating point tricks. Its 5 times faster than Math.exp() on my machine, but this can vary drastically if you compile with -server.

martinus