javascripthyperbolic-function

Tanh returning NaN for large input?


In my node.js program, I ran this code

console.log(Math.tanh(-858.625086043538));

and it returned NaN. Yet, tanh (hyperbolic tangent) http://mathworld.wolfram.com/HyperbolicTangent.html is defined for all x. It should just return -1, but its giving NaN. Does anyone know whats wrong?

Thanks


Solution

  • Looks like a bad implementation in Node.js (v5.4.1) version of V8 (4.6.85.31) which is taking e^(+/-x) which, for an input that larger, results in the return of (-Infinity / Infinity) which, further, is NaN.

    The good news is this was fixed in V8 version v4.8.87 with a commit that moved to a js fdlibm port. This is why it works in your current-version Chrome DevTools.

    If you cannot wait until Node.js pulls in the latest V8, you can port over the current V8 implementation into your own code (which is based on this port of fdlibm), which seems to work fine. You just run the risk of any fixes or changes to the real V8 Math.tanh that may occur in the future. Here's the V8/fdlibm port:

    Math.tanh = function (x) {
      x = x * 1;  // Convert to number.
      // x is Infinity or NaN
      if (!Math.abs(x) === Infinity) {
        if (x > 0) return 1;
        if (x < 0) return -1;
        return x;
      }
      var ax = Math.abs(x);
      var z;
      // |x| < 22
      if (ax < 22) {
        var twoM55 = 2.77555756156289135105e-17; // 2^-55, empty lower half
        if (ax < twoM55) {
          // |x| < 2^-55, tanh(small) = small.
          return x;
        }
        if (ax >= 1) {
          // |x| >= 1
          var t = Math.exp(2 * ax);
          z = 1 - 2 / (t + 2);
        } else {
          var t = Math.exp(-2 * ax);
          z = -t / (t + 2);
        }
      } else {
        // |x| > 22, return +/- 1
        z = 1;
      }
      return (x >= 0) ? z : -z;
    };