Быстрое гиперболическое касательное приближение в Javascript

Я делаю некоторые вычисления цифровой обработки сигналов в javascript, и я обнаружил, что вычисление гиперболического тангенса (Танха) - это слишком дорого. Вот как я сейчас приближаюсь Танха:

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

кто-нибудь знает более быстрый способ, чтобы вычислить это?

8 ответов


С здесь.

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 с tweaked коэффициенты.

функция находится в диапазоне x=-3..Три и выводит диапазон y=-1..1. За этот диапазон выход должен быть зажат в-1..1.

первые производные функция исчезает на -3 и 3, поэтому переход к жестко обрезанная область является С2-постоянная.

приближение паде на величины лучше, чем разложение Тейлора. Зажимать может также быть вопросом (в зависимости от вашего ряда).


вы могли бы сделать это и сократить время работы в два раза:

function tanh(arg) {
    var pos = Math.exp(arg);
    var neg = Math.exp(-arg);
    return (pos - neg) / (pos + neg);
}

не уверен, насколько большим будет увеличение производительности, но

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

вы сократите количество exps пополам.


вы всегда можете отключить формулу на определенном уровне точности.

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

Это мой ответ на эту проблему

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, и расширяя логистическую функцию, вы получаете:

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

Я не знаю, быстрее ли это в javascript.


вызов этой функции в 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 этот подход дает очень ненадежные результаты...


ES6 предоставляет этот метод и многие другие тригонометрические функции изначально:

  • Math.sinh – гиперболический синус числа
  • Math.cosh – гиперболический Косинус ряд
  • Math.tanh - гиперболический тангенс числа
  • Math.asinh – гиперболическая дуга-синус числа
  • Math.acosh – гиперболический дуговой Косинус числа
  • Math.atanh – гиперболическая дуга-касательная числа
  • Math.hypot – квадратный корень сумма квадратов

скорее всего, это будет быстрее, чем большинство альтернатив JS.