Быстрое гиперболическое касательное приближение в 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)
вы сократите количество exp
s пополам.
вы всегда можете отключить формулу на определенном уровне точности.
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.