11
votes

Approximation de tangente hyperbolique rapide en JavaScript

Je fais des calculs de traitement du signal numérique en JavaScript, et j'ai trouvé que calculer le tangent hyperbolique ( tanh ) est un peu trop coûteux. C'est comme ça que j'approche actuellement tanh : xxx

Quelqu'un sait un moyen plus rapide de le calculer?


2 commentaires

Vous devez spécifier deux informations clés d'informations (a) quel est le domaine de votre argument d'entrée (B) quelle précision dont vous avez besoin.


Maintenant, ES6 fournit ce Nativement.


8 Réponses :


6
votes

Vous pouvez le faire et couper votre temps de performance en deux :

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


2 commentaires

En FF4, le test était de 41% plus lentement pour votre solution :(


@janesconference: whoa! Je vois cela aussi dans FF4 - J'ai vu la performance boost en utilisant Chrome.



4
votes

Vous n'êtes pas sûr de la taille de l'augmentation de la performance, mais

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


0 commentaires

1
votes

Vous pouvez toujours couper la formule à un certain nombre de précision de précision.

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


4 commentaires

La précision de l'expansion Taylor est plutôt mauvais cependant.


D'accord. C'est une tonne plus rapide, mais cela dépend vraiment.


arg est x, je suppose? Ceci est très utile. Pourriez-vous me signaler à une règle générale pour couper la formule à un niveau de précision arbitraire?


Oui désolé. x est arg . L'expansion générale Taylor est Wolframalpha.com/input/?i=tanh .



14
votes

de ici .

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 );
}


5 commentaires

Super! Et si j'ai une gamme arbitraire? Simplement la mise à l'échelle des coefficients serait juste? (par exemple: plage [-1,1] -> retour x * (9 + x * x) / (9 + 3 * x * x))


Je ne le pense pas. D'après ce que je comprends, 3 ont été choisis parce que les deux premiers dérivés disparaissent à -3 et 3 (rappelez-vous que nous n'utilisons que les 3 premiers éléments de l'approximation). Je ne pense pas que l'échelle des coefficients donnera le résultat souhaité.


@janesconference, je viens de le graphiquement pour vérifier et yeah, vous ne voulez pas faire cela :)


@janesconference pour les coiffes extérieures utilisez Taylor


Tracé (sans clips à 3) fooplot.com/...



0
votes

appelant que la fonction sur chrome prend moins de trois fois de ce qu'il faut pour appeler une fonction vide f () {} donc je pense que vous n'allez pas gagner beaucoup avec une réécriture. < p> Le problème est la fonction de fonction, pas la formule. Peut-être que l'inlinisation peut sauver quelque chose de plus intéressant ...

Modifier

Pour faire le test Ce que j'ai fait, il suffisait d'ouvrir une console dans chrome (Ctrl-Shift-C) et créé une fonction de synchronisation avec xxx

puis le testé avec la fonction () {} et avec votre fonction.

Il tourne Cependant, ce type de test est très peu fiable. J'ai même eu des résultats absurdes avec TimeIt (F1) Rapport 200 et TimeIt (F2) Rapport 120 (assez différence) Mais F1 et F2 étaient en effet deux variables liées à l'objet de la même fonction. Il y avait aussi une différence entre TimeIt (f) et TIMINIT (fonction (x) {renvoyer math.cos (x);}) même lorsque f était exactement cette fonction.

peut être une explication en raison de la manière dont V8 et la console JavaScript interagissent, mais je ne sais pas ce que c'est.

aussi avec FF4 Ceci L'approche donne des résultats très peu fiables ...


1 commentaires

Je vais essayer ça. Au fait, comment avez-vous profilé cela? (Je suis sur FF4 et je fais le profilage avec Firebug)



1
votes

Ceci est ma réponse à ce problème

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

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


0 commentaires

2
votes

Pour une réponse précise en utilisant moins de math.exp () code> s, vous pouvez utiliser la relation entre TANH et le fonction logistique . tanh (x) code> est exactement 2 * logistique (2 * x) - 1 code> et élargir la fonction logistique, vous obtenez:

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


0 commentaires

2
votes

ES6 fournit cette méthode et bien d'autres fonctions trigonométriques nativement:

  • math.sinh - Sine hyperbolique d'un nombre
  • math.cosh - cosinus hyperbolique d'un nombre
  • math.tanh - tangente hyperbolique d'un nombre
  • math.asinh - Arc hyperbolique d'un nombre
  • math.acosh - arc hyperbolique-cosinine d'un nombre
  • math.atanh - arc hyperbolique d'un nombre
  • math.hypot - racine carrée de la somme des carrés

    Très probablement, ce serait plus rapide que la plupart des alternatives JS.


0 commentaires