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 函数的 pade 近似。

该函数在 x=-3..3 范围内并输出 y=-1..1 范围。超出此范围,输出必须钳位到 -1..1。

函数的一阶导数在 -3 和 3 处消失,因此到硬裁剪区域的过渡是 C2 连续的。

Padé 近似比泰勒展开要好几个数量级。夹紧也可能是一个问题(取决于您的范围)。

于 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)

您会将exps 的数量减少一半。

于 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 上调用该函数所需的时间不到调用空函数的三倍,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 和timeit(f2)报告 120 的荒谬结果(相当不同),但f1确实f2是两个变量链接到同一个函数对象。timeit(f)同样,该功能之间甚至timeit(function(x){ return Math.cos(x); })何时都存在差异f

由于 V8 和 javascript 控制台如何交互,可能会有解释,但我不知道它是什么。

同样对于 FF4,这种方法会给出非常不可靠的结果......

于 2011-05-24T23:43:18.750 回答