Javascript中的快速双曲正切逼近

Javascript中的快速双曲正切逼近,javascript,performance,math,approximation,Javascript,Performance,Math,Approximation,我正在用javascript进行一些数字信号处理计算,我发现计算双曲正切(tanh)有点太贵了。这就是我目前估计tanh的方法: function tanh (arg) { // sinh(number)/cosh(number) return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg)); } 有人知道一种更快的计算方法吗?您可以这样做: 不确定性能提升的幅度有多大,但是 (exp(x)

我正在用javascript进行一些数字信号处理计算,我发现计算双曲正切(tanh)有点太贵了。这就是我目前估计tanh的方法:

function tanh (arg) {
    // sinh(number)/cosh(number)
    return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
}
有人知道一种更快的计算方法吗?

您可以这样做:


不确定性能提升的幅度有多大,但是

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

您将把
exp
s的数量减半。

您始终可以在一定的精度级别上切断公式

function tanh (x) {
    return arg - (x * x * x / 3) + (2 * x * x * x * x * x / 15);
}

函数有理数(x) { 如果(x<-3) 返回-1; 如果(x>3),则为else 返回1; 其他的 返回x*(27+x*x)/(27+9*x*x); } 这是一个合理的函数 近似棕褐色的软剪刀。 它基于帕德近似 使用调整的tanh函数的 系数

函数的范围为x=-3..3 并输出范围y=-1..1。超过 此范围必须限制输出 到-1..1

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


Padé近似比Taylor展开好几个数量级。钳位也可能是一个问题(取决于您的范围)。

在chrome上调用该函数所需的时间不到调用空
函数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;
}
timeit=function(f){
var start=(新日期).getTime();

对于(var i=0;i这是我对这个问题的答案

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

Math.constructor.prototype.tanh=tanh;
document.write(Math.tanh(2))

要使用较少的
Math.exp()
s获得准确的答案,可以使用tanh和之间的关系。
tanh(x)
正好是
2*logistic(2*x)-1
,并展开logistic函数,您可以得到:

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

不过,我不知道在javascript中这是否更快。

ES6本机提供了此方法和许多其他trig函数:

  • Math.sinh
    –数字的双曲正弦
  • Math.cosh
    –数字的双曲余弦
  • Math.tanh
    –数字的双曲正切
  • Math.asinh
    –数字的双曲弧正弦
  • Math.acosh
    –数字的双曲弧余弦
  • Math.atanh
    –数字的双曲正切
  • Math.hypot
    –平方和的平方根

最有可能的是,它比大多数JS替代方案都快。

泰勒展开式的精度是。同意。它快了一吨,但它确实取决于。我想arg是x?这非常有用。你能给我指出一条将公式切割到任意精度水平的一般规则吗?是的,对不起。
x
arg
一般泰勒展开式很好!如果我有一个任意的范围呢?简单地缩放系数是正确的?(例如:范围[-1,1]>返回x*(9+x*x)/(9+3*x*x)),我不这么认为。据我所知,选择3是因为前两个导数在-3和3处消失(请记住,我们只使用了近似值中的前3个元素)。我认为缩放系数不会得到期望的结果。@janesconference,我只是将其绘制为双重检查,是的,您不想这样做:)@janesconference对于外部范围系数使用taylorPlotted(在3处没有剪辑)我要试试。顺便问一下,你是如何分析的?(我在ff4上,我用firebug进行分析)在ff4中,你的解决方案的测试速度慢了41%:(@janesconference:哇!我在ff4中也看到了这一点-我看到了使用Chrome的性能提升。你需要指定两个关键信息(a)输入参数的域是什么,(b)你需要多精确,现在。
function tanh(x){
     var e = Math.exp(2*x)
     return (e-1)/(e+1)
}

Math.constructor.prototype.tanh=tanh;
document.write(Math.tanh(2))
  function one_exp_tanh(x){
      return 2.0 / (1.0 + exp(-2.0 * x)) - 1.0;
  }