Port fdlibm implementation for Math.cosh.
authoryangguo@chromium.org <yangguo@chromium.org>
Mon, 1 Sep 2014 09:36:00 +0000 (09:36 +0000)
committeryangguo@chromium.org <yangguo@chromium.org>
Mon, 1 Sep 2014 09:36:00 +0000 (09:36 +0000)
R=rtoy@chromium.org
BUG=v8:3494
LOG=N

Review URL: https://codereview.chromium.org/522723002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23548 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/math.js
test/mjsunit/es6/math-hyperbolic.js
third_party/fdlibm/fdlibm.cc
third_party/fdlibm/fdlibm.js
tools/generate-runtime-tests.py

index 008a41e..f06249d 100644 (file)
@@ -186,13 +186,6 @@ function MathTrunc(x) {
   return x;
 }
 
-// ES6 draft 09-27-13, section 20.2.2.12.
-function MathCosh(x) {
-  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
-  if (!NUMBER_IS_FINITE(x)) return MathAbs(x);
-  return (MathExp(x) + MathExp(-x)) / 2;
-}
-
 // ES6 draft 09-27-13, section 20.2.2.33.
 function MathTanh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -369,7 +362,7 @@ function SetUpMath() {
     "sign", MathSign,
     "trunc", MathTrunc,
     "sinh", MathSinh,     // implemented by third_party/fdlibm
-    "cosh", MathCosh,
+    "cosh", MathCosh,     // implemented by third_party/fdlibm
     "tanh", MathTanh,
     "asinh", MathAsinh,
     "acosh", MathAcosh,
index 1632e00..5574799 100644 (file)
@@ -102,13 +102,13 @@ assertEquals("Infinity", String(Math.acosh(Infinity)));
 
 
 // Some random samples.
-assertEqualsDelta(74.203210577788, Math.sinh(5), 1E-12);
-assertEqualsDelta(-74.203210577788, Math.sinh(-5), 1E-12);
+assertEqualsDelta(74.20321057778875, Math.sinh(5), 1E-12);
+assertEqualsDelta(-74.20321057778875, Math.sinh(-5), 1E-12);
 
-assertEqualsDelta(1.1276259652063, Math.cosh(0.5), 1E-12);
-assertEqualsDelta(74.209948524787, Math.cosh(5), 1E-12);
-assertEqualsDelta(1.1276259652063, Math.cosh(-0.5), 1E-12);
-assertEqualsDelta(74.209948524787, Math.cosh(-5), 1E-12);
+assertEqualsDelta(1.1276259652063807, Math.cosh(0.5), 1E-12);
+assertEqualsDelta(74.20994852478785, Math.cosh(5), 1E-12);
+assertEqualsDelta1.1276259652063807, Math.cosh(-0.5), 1E-12);
+assertEqualsDelta(74.20994852478785, Math.cosh(-5), 1E-12);
 
 assertEqualsDelta(0.4621171572600, Math.tanh(0.5), 1E-12);
 assertEqualsDelta(0.9999092042625, Math.tanh(5), 1E-12);
@@ -166,3 +166,23 @@ assertEquals(Infinity, Math.sinh(710.475860073944));
 assertEquals(-Infinity, Math.sinh(-710.475860073944));
 assertEquals(Infinity, Math.sinh(1000));
 assertEquals(-Infinity, Math.sinh(-1000));
+
+// Implementation-specific tests for cosh.
+// Case |x| < 2^-55
+assertEquals(1, Math.cosh(Math.pow(2, -56)));
+assertEquals(1, Math.cosh(-Math.pow(2, -56)));
+// Case |x| < 1/2*log(2). cosh(Math.LN2/4) = (sqrt(2)+1)/2^(5/4)
+assertEquals(1.0150517651282178, Math.cosh(Math.LN2/4));
+assertEquals(1.0150517651282178, Math.cosh(-Math.LN2/4));
+// Case 1/2*log(2) < |x| < 22. cosh(10*Math.LN2) = 1048577/2048
+assertEquals(512.00048828125, Math.cosh(10*Math.LN2));
+assertEquals(512.00048828125, Math.cosh(-10*Math.LN2));
+// Case 22 <= |x| < log(maxdouble)
+assertEquals(2.1474836479999983e9, Math.cosh(32*Math.LN2));
+assertEquals(2.1474836479999983e9, Math.cosh(-32*Math.LN2));
+// Case log(maxdouble) <= |x| <= overflowthreshold
+assertEquals(1.7976931348621744e308, Math.cosh(710.4758600739439));
+assertEquals(1.7976931348621744e308, Math.cosh(-710.4758600739439));
+// Overflow.
+assertEquals(Infinity, Math.cosh(710.475860073944));
+assertEquals(Infinity, Math.cosh(-710.475860073944));
index 67c1b72..c009cd0 100644 (file)
@@ -79,7 +79,7 @@ const double MathConstants::constants[] = {
     -7.93650757867487942473e-05,  //          49
     4.00821782732936239552e-06,   //          50
     -2.01099218183624371326e-07,  // Q5       51
-    710.4758600739439             //          52  overflow threshold for sinh
+    710.4758600739439             //          52  overflow threshold sinh, cosh
 };
 
 
index 95ea5f4..08c6f5e 100644 (file)
@@ -759,3 +759,56 @@ function MathSinh(x) {
   // Return Infinity of the appropriate sign or NaN.
   return x * INFINITY;
 }
+
+
+// ES6 draft 09-27-13, section 20.2.2.12.
+// Math.cosh
+// Method : 
+// mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+//      1. Replace x by |x| (cosh(x) = cosh(-x)). 
+//      2.
+//                                                      [ exp(x) - 1 ]^2 
+//          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+//                                                         2*exp(x)
+//
+//                                                 exp(x) + 1/exp(x)
+//          ln2/2    <= x <= 22     :  cosh(x) := -------------------
+//                                                        2
+//          22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+//          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+//          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
+//
+// Special cases:
+//      cosh(x) is |x| if x is +INF, -INF, or NaN.
+//      only cosh(0)=1 is exact for finite x.
+//
+const KCOSH_OVERFLOW = kMath[52];
+
+function MathCosh(x) {
+  x = x * 1;  // Convert to number.
+  var ix = %_DoubleHi(x) & 0x7fffffff;
+  // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|))
+  if (ix < 0x3fd62e43) {
+    var t = MathExpm1(MathAbs(x));
+    var w = 1 + t;
+    // For |x| < 2^-55, cosh(x) = 1
+    if (ix < 0x3c800000) return w;
+    return 1 + (t * t) / (w + w);
+  }
+  // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
+  if (ix < 0x40360000) {
+    var t = MathExp(MathAbs(x));
+    return 0.5 * t + 0.5 / t;
+  }
+  // |x| in [22, log(maxdouble)], return half*exp(|x|)
+  if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
+  // |x| in [log(maxdouble), overflowthreshold]
+  if (MathAbs(x) <= KCOSH_OVERFLOW) {
+    var w = MathExp(0.5 * MathAbs(x));
+    var t = 0.5 * w;
+    return t * w;
+  }
+  if (NUMBER_IS_NAN(x)) return x;
+  // |x| > overflowthreshold.
+  return INFINITY;
+}
index 7efcf8c..638c4ae 100755 (executable)
@@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 431
 EXPECTED_FUZZABLE_COUNT = 332
 EXPECTED_CCTEST_COUNT = 7
 EXPECTED_UNKNOWN_COUNT = 17
-EXPECTED_BUILTINS_COUNT = 807
+EXPECTED_BUILTINS_COUNT = 806
 
 
 # Don't call these at all.