我正在挖掘一些Java数学函数原生C源代码。特别是tanh()
,因为我很好奇他们是如何实现这一点的。 然而,what I found出乎我的意料:Java/C:OpenJDK本地tanh()实现错误?
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
(这将是快),如图所示由该曲线:
(粗线是一个在顶部指示。另一个灰色的是log(abs(x(1+x) - tanh(x)))
。该sigmoid当然是tanh(x)
本身)。
所以,这是一个在实施中的错误,或者这是一个黑客来解决一些问题(如数字问题,我不能真正想到)?请注意,我期望这两种方法的结果完全相同,因为没有足够的mantisse位实际执行加法1 + x,因为x < 2 ^( - 55)。
这是一种导致火箭爆炸的垃圾。 –
完全期望'tanh()'是一个_odd_函数,所以'y = f(x) - > y = -f(-x)'。 'x + x^2'打破了这一点。唯一的想法是在'f(-0.0)'上强制一个+符号,但是这很容易处理'tanh(x)= x + 0.0;'。国际海事组织,一个错误,可能不会显示为“| x | <2 ** - 55”......或与舍入标志有关。 – chux
在目标平台上'x *(one + x)'是否会影响'x + 0.0'? – chux