我正在研究一些Java Math函数的 native C源代码。尤其是tanh(),我很想知道他们是如何实现的。
但是,what I found让我感到惊讶:

double tanh(double x) {
    ...
    if (ix < 0x40360000) {          /* |x|<22 */
        if (ix<0x3c800000)          /* |x|<2**-55 */
            return x*(one+x);       /* tanh(small) = small */
    ...
}

如注释所示,taylor series of tanh(x) around 0开头为:
tanh(x) = x - x^3/3 + ...

那么为什么看起来像他们那样实现它:
tanh(x) = x * (1 + x)
        = x + x^2

显然,这不是正确的扩展,甚至比仅使用tanh(x) = x(这会更快)的近似值还要差,如下图所示:

Java/C : OpenJDK native tanh() implementation wrong?-LMLPHP

(粗线是在顶部指示的线。另一条灰色是log(abs(x(1+x) - tanh(x)))。Sig当然是tanh(x)本身。)

那么,这是实现中的错误,还是解决某些问题(例如数字问题,我真的没想到)的破解工具?请注意,我希望两种方法的结果都完全相同,因为对于x
编辑:I will include a link to the version of the code at the time of writing, for future reference, as this might get fixed.

最佳答案

在执行该代码的条件下,并假设正在使用IEEE-754 double 浮点表示和算术,1.0 + x将始终求值为1.0,因此x * (1.0 + x)始终将求值为x。像执行此操作一样,从外部(对于函数)可观察到的唯一效果(不仅仅是返回x)将是设置IEEE“inexact”状态标志。

尽管我不知道从Java查询FP状态标志的方法,但可以想象其他 native 代码也可以查询它们。但是,很可能通过the Javadocs for java.StrictMath 中的这些注释来给出实现的实际原因:



(添加了强调。)您将在C源代码中注意到一个#include "fdlibm.h",它似乎将其与Javadoc注释联系在一起。

关于Java/C : OpenJDK native tanh() implementation wrong?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41818255/

10-10 15:14