私はいくつかの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 * (1 + x)
= x + x^2
:彼らはとしてそれを実装よう
tanh(x) = x - x^3/3 + ...
そして、なぜそれが見えません明らかに正しい拡張ではなく、ちょうどtanh(x) = x
を使用するよりも悪い近似さえあります速い)、このプロットで示されるように:
(太字の行は上部に表示するものです。他の灰色のものはlog(abs(x(1+x) - tanh(x)))
です。 Sigmoidはもちろんtanh(x)
です。
これは実装上のバグですか、これはいくつかの問題を解決するためのハックです(数値的な問題のように私は本当に考えることができません)。 2つのアプローチの結果は、x < 2 ^( - 55)に対して実際に加算1 + xを実行するのに十分なmantisseビットがないのとまったく同じであると期待していることに注意してください。
EDIT:そのコードが実行される条件下でI will include a link to the version of the code at the time of writing, for future reference, as this might get fixed.
ロケットが爆発するのはこのようなものです。 –
'tanh()'が_odd_関数であることを完全に想定しているので、 'y = f(x) - > y = -f(-x)'です。 'x + x^2'はそれを破ります。唯一の考えは 'f(-0.0)'に+記号を強制することですが、これは 'tanh(x)= x + 0.0;'で簡単に行うことができます。 IMO、それ自体が '| x | <2 ** - 55' ...または丸めフラグと関係していないエラーです。 – chux
'x *(one + x)'は、ターゲットプラットフォームで 'x + 0.0'を実行するのに難しい方法でしょうか? – chux