通过JNI更快的Math.exp()吗?
我需要非常频繁地从Java计算Math.exp()
,是否有可能使本机版本比Java的Math.exp()
运行得更快?
我只尝试了jni + C,但是它比纯java慢。
解决方案
回答
使用Java的。
另外,缓存exp的结果,然后我们可以比重新计算更快地查找答案。
回答
我们还希望将任何循环调用Math.exp()
都包装在C中。否则,在Java和C之间进行编组的开销将压倒任何性能优势。
回答
由于Java代码将通过即时(JIT)编译器编译为本地代码,因此实际上没有理由使用JNI来调用本地代码。
另外,我们不应缓存输入参数为浮点实数的方法的结果。及时获得的收益将在使用的空间量上大量损失。
回答
使用JNI的问题是调用JNI所涉及的开销。如今,Java虚拟机已进行了非常优化,并且对内置Math.exp()的调用已自动进行了优化,以直接调用C exp()函数,甚至可以将它们优化为直接x87浮点程序集指示。
回答
真正的问题是,这成为瓶颈吗?我们是否已对应用程序进行了概要分析,并发现这是速度下降的主要原因?
回答
如果没有,我建议使用Java版本。尽量不要进行预优化,因为这只会导致开发速度变慢。我们可能会花较长的时间解决可能不是问题的问题。
话虽如此,我认为测试给了我们答案。如果jni + C较慢,请使用Java版本。
使用JNI只会产生一些开销,另请参见:
http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html
回答
因此,正如其他人建议的那样,请尝试整理涉及使用JNI的操作。
回答
如果分批执行,则可能使它运行得更快。进行JNI调用会增加开销,因此我们不想为需要计算的每个exp()都这样做。我会尝试传递100个值的数组,并获取结果以查看它是否对性能有所帮助。
编写自己的,并根据需求量身定制。
回答
例如,如果所有指数都是2的幂,则可以使用位移。如果我们使用有限的范围或者一组值,则可以使用查找表。如果不需要精确度,则可以使用不精确但速度更快的算法。
跨越JNI边界进行调用会产生一定的成本。
如果我们也可以将调用exp()的循环也移到本机代码中,以便只有一个本机调用,则可能会得到更好的结果,但是我怀疑它会比纯Java解决方案快得多。
回答
我不知道应用程序的详细信息,但是如果调用的可能参数集相当有限,则可以使用预先计算的查找表来加快Java代码的速度。
根据我们要完成的工作,有更快的exp算法。问题空间是否限制在特定范围内,我们是否仅需要特定的分辨率,精度或者准确性等?
如果我们很好地定义了问题,则可能会发现我们可以使用带有插值的表,例如,该表将使几乎所有其他算法无效。
我们可以对exp应用哪些约束来获得性能折衷?
回答
-亚当
+1以编写自己的exp()实现。也就是说,如果这确实是我们应用程序中的瓶颈。如果我们可以解决一些不准确的问题,那么这里有许多非常有效的指数估计算法,其中一些可以追溯到几个世纪以前。据我了解,即使对于必须返回"精确"结果的算法,Java的exp()实现也相当慢。
回答
I run a fitting algorithm and the minimum error of the fitting result is way larger than the precision of the Math.exp().
哦,不要害怕用纯Java编写该exp()实现。 JNI有很多开销,并且JVM有时甚至可以在C / C ++不能实现的情况下在运行时优化字节码。
先验功能总是比加法或者乘法慢得多,并且是众所周知的瓶颈。如果知道值在狭窄范围内,则可以简单地建立一个查找表(两个排序数组;一个输入,一个输出)。使用Arrays.binarySearch查找正确的索引,并使用[index]和[index + 1]处的元素插入值。
另一种方法是拆分数字。让我们以3.81并将其拆分为3 + 0.81.
现在,将e = 2.718乘以三倍,得到20.08.
现在为0.81. 0到1之间的所有值都以众所周知的指数级数快速收敛
1 + x + x ^ 2/2 + x ^ 3/6 + x ^ 4/24 ...等
尽可能多地考虑精度要求;不幸的是,如果x接近1,速度会变慢。假设我们转到x ^ 4,则得到的是2.2445,而不是正确的2.2448
回答
然后将结果2.781 ^ 3 = 20.08乘以2.781 ^ 0.81 = 2.2445,就得到了结果
45.07,错误为2000的一部分(正确:45.15)。
public static double exp(double val) { final long tmp = (long) (1512775 * val + (1072693248 - 60801)); return Double.longBitsToDouble(tmp << 32); }
已经多次请求了此请求(请参见此处)。这是从此博客文章中复制的Math.exp()的近似值:
段落数量不匹配