11

私は JavaScript でいくつかのデジタル信号処理計算を行っていますが、双曲線正接 ( tanh ) の計算は少しコストがかかりすぎることがわかりました。これは私が現在tanhを概算する方法です:

function tanh (arg) {
    // sinh(number)/cosh(number)
    return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
}

より速く計算する方法を知っている人はいますか?

4

8 に答える 8

14

ここから。

function rational_tanh(x)
{
    if( x < -3 )
        return -1;
    else if( x > 3 )
        return 1;
    else
        return x * ( 27 + x * x ) / ( 27 + 9 * x * x );
}

これは、tanh のようなソフト クリッパーを近似する有理関数です。これは、微調整された係数を使用した tanh 関数のパデ近似に基づいています。

関数は範囲 x=-3..3 にあり、範囲 y=-1..1 を出力します。この範囲を超えると、出力を -1..1 にクランプする必要があります。

関数の導関数の 1 番目から 3 番目は -3 と 3 で消失するため、ハード クリップ領域への遷移は C2 連続です。

パデ近似は、テイラー展開よりも優れています。クランピングも問題になる場合があります (範囲によっては)。

于 2011-05-24T23:39:31.383 に答える
6

これを行うと、パフォーマンス時間を半分に短縮できます

function tanh(arg) {
    var pos = Math.exp(arg);
    var neg = Math.exp(-arg);
    return (pos - neg) / (pos + neg);
}
于 2011-05-24T23:32:43.817 に答える
4

パフォーマンスがどれだけ向上するかはわかりませんが、

(exp(x) - exp(-x))/(exp(x) + exp(-x)) = (exp(2x) - 1)/(exp(2x) + 1)

sの数をexp半分に減らします。

于 2011-05-24T23:34:07.470 に答える
2

より少ない s を使用して正確な答えを得るには、tanh とロジスティック関数Math.exp()の関係を使用できます。は正確に であり、ロジスティック関数を展開すると、次のようになります。Tanh(x)2 * logistic(2 * x) - 1

  function one_exp_tanh(x){
      return 2.0 / (1.0 + exp(-2.0 * x)) - 1.0;
  }

ただし、それがjavascriptの方が速いかどうかはわかりません。

于 2013-07-18T04:22:56.770 に答える
2

ES6 は、このメソッドと他の多くのトリガー関数をネイティブに提供します。

  • Math.sinh– 数値の双曲線正弦
  • Math.cosh– 数値の双曲線余弦
  • Math.tanh– 数値の双曲線正接
  • Math.asinh– 数値の双曲線逆正弦
  • Math.acosh– 数値の双曲線逆余弦
  • Math.atanh– 数値の双曲線逆正接
  • Math.hypot– 二乗和の平方根

おそらく、ほとんどの JS 代替よりも高速です。

于 2015-11-08T07:49:11.200 に答える
1

特定の数値レベルの精度でいつでも式を切り取ることができます。

function tanh (x) {
    return arg - (x * x * x / 3) + (2 * x * x * x * x * x / 15);
}
于 2011-05-24T23:35:29.150 に答える
1

これがこの問題に対する私の答えです

function tanh(x){
     var e = Math.exp(2*x)
     return (e-1)/(e+1)
}

Math.constructor.prototype.tanh=tanh;
document.write(Math.tanh(2))
于 2012-01-05T04:47:25.707 に答える
0

chrome でその関数を呼び出すと、空の関数を呼び出すのにかかる時間の 3 倍もかからないfunction f(){}ので、書き直してもあまりメリットがないと思います。

問題は関数のオーバーヘッドであり、数式ではありません。インライン化することで、もっと興味深いものを保存できる可能性があります...

編集

テストを行うには、Chrome でコンソールを開き (ctrl-shift-C)、タイミング関数を作成するだけでした。

timeit = function(f) {
     var start=(new Date).getTime();
     for (var i=0; i<100000; i++)
         f(1);
     return (new Date).getTime() - start;
}

function(){}次に、関数を使用してテストしました。

ただし、この種のテストは非常に信頼性が低いことが判明しています。timeit(f1)200 を報告し、120 を報告してもばかげた結果が得られましたがtimeit(f2)(かなりの違いです)、実際f1f2は同じ関数オブジェクトにリンクされた 2 つの変数でした。また、正確にその機能であった場合でも、timeit(f)との間に違いがありました。timeit(function(x){ return Math.cos(x); })f

V8 と JavaScript コンソールがどのように相互作用するかについての説明があるかもしれませんが、それが何であるかはわかりません。

また、FF4では、このアプローチは非常に信頼できない結果をもたらします...

于 2011-05-24T23:43:18.750 に答える