代码之家  ›  专栏  ›  技术社区  ›  Dan

通过JNI提高Math.exp()的速度?

  •  10
  • Dan  · 技术社区  · 16 年前

    我需要计算一下 Math.exp() 经常使用java,是否有可能使本机版本的运行速度比 JAVA Math.exp() ??

    我尝试了jni+C,但是比普通的要慢 JAVA

    15 回复  |  直到 10 年前
        1
  •  15
  •   Community CDub    8 年前

    here )。这是Math.exp()的近似值,复制自 this blog posting :

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

    它基本上与具有2048个条目和条目之间的线性插值的查找表相同,但所有这些都使用IEEE浮点技巧。它比我机器上的Math.exp()快5倍,但如果使用-server编译,速度可能会有很大的变化。

        2
  •  12
  •   Daniel Spiewak    16 年前

    +1编写自己的exp()实现。就是如果这是 真正地 应用程序中的瓶颈。如果你能处理一些不精确的问题,有很多非常有效的指数估计算法,其中一些可以追溯到几个世纪前。据我所知,Java的exp()实现相当慢,即使对于必须返回“精确”结果的算法也是如此。

    哦,不要害怕用纯Java编写exp()实现。JNI有很多开销,JVM能够在运行时优化字节码,有时甚至超过C/C++的能力。

        3
  •  6
  •   jjnguy Julien Chastang    16 年前

    使用Java的。

    此外,缓存exp的结果,然后您可以比再次计算更快地查找答案。

        4
  •  5
  •   John Millikin    16 年前

    你会想结束任何循环调用的 Math.exp() 在C中也是如此。否则,Java和C之间的编组开销将压倒任何性能优势。

        5
  •  3
  •   Bill the Lizard    16 年前

    如果分批进行,您可能可以让它运行得更快。进行JNI调用会增加开销,因此您不希望对需要计算的每个exp()都进行调用。我会尝试传递一个包含100个值的数组,然后得到结果,看看它是否有助于提高性能。

        6
  •  2
  •   scubabbl    16 年前

    真正的问题是,这是否成为你的瓶颈?您是否分析过您的应用程序并发现这是导致速度减慢的主要原因?

    如果不是,我建议使用Java的版本。尽量不要预先优化,因为这只会导致开发速度减慢。你可能会花很长时间在一个可能不是问题的问题上。

    尽管如此,我认为你的测试给了你答案。如果jni+C速度较慢,请使用java版本。

        7
  •  2
  •   Renaud    11 年前

    Commons Math3 随附优化版本: FastMath.exp(double x) . 它确实大大加快了我的代码速度。

    Fabien Math.exp() :

     0.75s for Math.exp     sum=1.7182816693332244E7
     0.40s for FastMath.exp sum=1.7182816693332244E7
    

    以下是javadoc:

    方法:

        Lookup intVal = exp(int(x))
        Lookup fracVal = exp(int(x-int(x) / 1024.0) * 1024.0 );
        Compute z as the exponential of the remaining bits by a polynomial minus one
        exp(x) = intVal * fracVal * (1 + z)
    

    精度:计算以63位精度完成,因此结果应正确四舍五入到99.9%的输入值,否则ULP误差小于1。

        8
  •  0
  •   Alan Krueger    16 年前

    由于Java代码将通过实时(JIT)编译器编译为本机代码,因此没有理由使用JNI调用本机代码。

    此外,您不应该缓存输入参数为浮点实数的方法的结果。在时间上获得的收益将在使用的空间量上损失很多。

        9
  •  0
  •   Adam Rosenfield    16 年前

    使用JNI的问题是调用JNI所涉及的开销。Java虚拟机现在已经非常优化了,对内置Math.exp()的调用会自动优化为直接调用C exp()函数,甚至可以优化为直接的x87浮点汇编指令。

        10
  •  0
  •   tonylo Germán Diago    16 年前

    http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html

    因此,正如其他人所建议的,尝试整理涉及使用JNI的操作。

        11
  •  0
  •   user9116    16 年前

    写你自己的,适合你的需要。

    例如,如果你所有的指数都是二的幂,你可以使用位移位。如果使用有限范围或一组值,则可以使用查找表。如果您不需要针点精度,可以使用不精确但更快的算法。

        12
  •  0
  •   Dan Dyer    16 年前

    跨越JNI边界进行调用会带来成本。

    如果您可以将调用exp()的循环也移动到本机代码中,这样就只有一个本机调用,那么您可能会得到更好的结果,但我怀疑它会比纯Java解决方案快得多。

    我不知道应用程序的细节,但是如果调用的可能参数集相当有限,那么可以使用预先计算的查找表来加快Java代码的速度。

        13
  •  0
  •   Adam Davis    16 年前

    exp有更快的算法,这取决于您的目标。问题空间是否限制在某个范围内,您是否只需要某个分辨率、精度或精度等。

    -亚当

        14
  •  0
  •   TSK    16 年前

    我运行了一个拟合算法,拟合结果的最小误差要大得多 大于Math.exp()的精度。

    超越函数总是比加法或乘法慢得多,这是一个众所周知的瓶颈。如果您知道您的值在一个狭窄的范围内,您可以简单地构建一个查找表(两个排序数组;一个输入,一个输出)。使用Arrays.binarySearch查找正确的索引,并使用[index]和[index+1]处的元素插值。

    另一种方法是分割数字。让我们以3.81为例,将其拆分为3+0.81。

    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,误差为两千分之一(正确:45.15)。

        15
  •  0
  •   reverse_engineer    12 年前

    它可能不再相关,但正如您所知,在OpenJDK的最新版本中(请参阅 here here ).

    这将使性能在大多数体系结构上无与伦比,因为这意味着Hotspot VM将在运行时用特定于处理器的exp实现取代对Math.exp的调用。您永远无法击败这些调用,因为它们针对体系结构进行了优化。。。

    推荐文章