1// The following is adapted from fdlibm (http://www.netlib.org/fdlibm),
2//
3// ====================================================
4// Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved.
5//
6// Developed at SunSoft, a Sun Microsystems, Inc. business.
7// Permission to use, copy, modify, and distribute this
8// software is freely granted, provided that this notice
9// is preserved.
10// ====================================================
11//
12// The original source code covered by the above license above has been
13// modified significantly by Google Inc.
14// Copyright 2014 the V8 project authors. All rights reserved.
15//
16// The following is a straightforward translation of fdlibm routines
17// by Raymond Toy (rtoy@google.com).
18
19// rempio2result is used as a container for return values of %RemPiO2. It is
20// initialized to a two-element Float64Array during genesis.
21
22(function(global, utils) {
23
24"use strict";
25
26%CheckIsBootstrapping();
27
28// -------------------------------------------------------------------
29// Imports
30
31var GlobalFloat64Array = global.Float64Array;
32var GlobalMath = global.Math;
33var MathAbs;
34var MathExp;
35var NaN = %GetRootNaN();
36var rempio2result;
37
38utils.Import(function(from) {
39  MathAbs = from.MathAbs;
40  MathExp = from.MathExp;
41});
42
43utils.CreateDoubleResultArray = function(global) {
44  rempio2result = new GlobalFloat64Array(2);
45};
46
47// -------------------------------------------------------------------
48
49define INVPIO2 = 6.36619772367581382433e-01;
50define PIO2_1  = 1.57079632673412561417;
51define PIO2_1T = 6.07710050650619224932e-11;
52define PIO2_2  = 6.07710050630396597660e-11;
53define PIO2_2T = 2.02226624879595063154e-21;
54define PIO2_3  = 2.02226624871116645580e-21;
55define PIO2_3T = 8.47842766036889956997e-32;
56define PIO4    = 7.85398163397448278999e-01;
57define PIO4LO  = 3.06161699786838301793e-17;
58
59// Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For
60// precision, r is returned as two values y0 and y1 such that r = y0 + y1
61// to more than double precision.
62
63macro REMPIO2(X)
64  var n, y0, y1;
65  var hx = %_DoubleHi(X);
66  var ix = hx & 0x7fffffff;
67
68  if (ix < 0x4002d97c) {
69    // |X| ~< 3*pi/4, special case with n = +/- 1
70    if (hx > 0) {
71      var z = X - PIO2_1;
72      if (ix != 0x3ff921fb) {
73        // 33+53 bit pi is good enough
74        y0 = z - PIO2_1T;
75        y1 = (z - y0) - PIO2_1T;
76      } else {
77        // near pi/2, use 33+33+53 bit pi
78        z -= PIO2_2;
79        y0 = z - PIO2_2T;
80        y1 = (z - y0) - PIO2_2T;
81      }
82      n = 1;
83    } else {
84      // Negative X
85      var z = X + PIO2_1;
86      if (ix != 0x3ff921fb) {
87        // 33+53 bit pi is good enough
88        y0 = z + PIO2_1T;
89        y1 = (z - y0) + PIO2_1T;
90      } else {
91        // near pi/2, use 33+33+53 bit pi
92        z += PIO2_2;
93        y0 = z + PIO2_2T;
94        y1 = (z - y0) + PIO2_2T;
95      }
96      n = -1;
97    }
98  } else if (ix <= 0x413921fb) {
99    // |X| ~<= 2^19*(pi/2), medium size
100    var t = MathAbs(X);
101    n = (t * INVPIO2 + 0.5) | 0;
102    var r = t - n * PIO2_1;
103    var w = n * PIO2_1T;
104    // First round good to 85 bit
105    y0 = r - w;
106    if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) {
107      // 2nd iteration needed, good to 118
108      t = r;
109      w = n * PIO2_2;
110      r = t - w;
111      w = n * PIO2_2T - ((t - r) - w);
112      y0 = r - w;
113      if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) {
114        // 3rd iteration needed. 151 bits accuracy
115        t = r;
116        w = n * PIO2_3;
117        r = t - w;
118        w = n * PIO2_3T - ((t - r) - w);
119        y0 = r - w;
120      }
121    }
122    y1 = (r - y0) - w;
123    if (hx < 0) {
124      n = -n;
125      y0 = -y0;
126      y1 = -y1;
127    }
128  } else {
129    // Need to do full Payne-Hanek reduction here.
130    n = %RemPiO2(X, rempio2result);
131    y0 = rempio2result[0];
132    y1 = rempio2result[1];
133  }
134endmacro
135
136
137// __kernel_sin(X, Y, IY)
138// kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
139// Input X is assumed to be bounded by ~pi/4 in magnitude.
140// Input Y is the tail of X so that x = X + Y.
141//
142// Algorithm
143//  1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x.
144//  2. ieee_sin(x) is approximated by a polynomial of degree 13 on
145//     [0,pi/4]
146//                           3            13
147//          sin(x) ~ x + S1*x + ... + S6*x
148//     where
149//
150//    |ieee_sin(x)    2     4     6     8     10     12  |     -58
151//    |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
152//    |  x                                               |
153//
154//  3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y
155//              ~ ieee_sin(X) + (1-X*X/2)*Y
156//     For better accuracy, let
157//               3      2      2      2      2
158//          r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6))))
159//     then                   3    2
160//          sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
161//
162define S1 = -1.66666666666666324348e-01;
163define S2 = 8.33333333332248946124e-03;
164define S3 = -1.98412698298579493134e-04;
165define S4 = 2.75573137070700676789e-06;
166define S5 = -2.50507602534068634195e-08;
167define S6 = 1.58969099521155010221e-10;
168
169macro RETURN_KERNELSIN(X, Y, SIGN)
170  var z = X * X;
171  var v = z * X;
172  var r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6)));
173  return (X - ((z * (0.5 * Y - v * r) - Y) - v * S1)) SIGN;
174endmacro
175
176// __kernel_cos(X, Y)
177// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
178// Input X is assumed to be bounded by ~pi/4 in magnitude.
179// Input Y is the tail of X so that x = X + Y.
180//
181// Algorithm
182//  1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x.
183//  2. ieee_cos(x) is approximated by a polynomial of degree 14 on
184//     [0,pi/4]
185//                                   4            14
186//          cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
187//     where the remez error is
188//
189//  |                   2     4     6     8     10    12     14 |     -58
190//  |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
191//  |                                                           |
192//
193//                 4     6     8     10    12     14
194//  3. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
195//         ieee_cos(x) = 1 - x*x/2 + r
196//     since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y
197//                    ~ ieee_cos(X) - X*Y,
198//     a correction term is necessary in ieee_cos(x) and hence
199//         cos(X+Y) = 1 - (X*X/2 - (r - X*Y))
200//     For better accuracy when x > 0.3, let qx = |x|/4 with
201//     the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
202//     Then
203//         cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)).
204//     Note that 1-qx and (X*X/2-qx) is EXACT here, and the
205//     magnitude of the latter is at least a quarter of X*X/2,
206//     thus, reducing the rounding error in the subtraction.
207//
208define C1 = 4.16666666666666019037e-02;
209define C2 = -1.38888888888741095749e-03;
210define C3 = 2.48015872894767294178e-05;
211define C4 = -2.75573143513906633035e-07;
212define C5 = 2.08757232129817482790e-09;
213define C6 = -1.13596475577881948265e-11;
214
215macro RETURN_KERNELCOS(X, Y, SIGN)
216  var ix = %_DoubleHi(X) & 0x7fffffff;
217  var z = X * X;
218  var r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6)))));
219  if (ix < 0x3fd33333) {  // |x| ~< 0.3
220    return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
221  } else {
222    var qx;
223    if (ix > 0x3fe90000) {  // |x| > 0.78125
224      qx = 0.28125;
225    } else {
226      qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0);
227    }
228    var hz = 0.5 * z - qx;
229    return (1 - qx - (hz - (z * r - X * Y))) SIGN;
230  }
231endmacro
232
233
234// kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
235// Input x is assumed to be bounded by ~pi/4 in magnitude.
236// Input y is the tail of x.
237// Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1)
238// is returned.
239//
240// Algorithm
241//  1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x.
242//  2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
243//  3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on
244//     [0,0.67434]
245//                           3             27
246//          tan(x) ~ x + T1*x + ... + T13*x
247//     where
248//
249//     |ieee_tan(x)    2     4            26   |     -59.2
250//     |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
251//     |  x                                    |
252//
253//     Note: ieee_tan(x+y) = ieee_tan(x) + tan'(x)*y
254//                    ~ ieee_tan(x) + (1+x*x)*y
255//     Therefore, for better accuracy in computing ieee_tan(x+y), let
256//               3      2      2       2       2
257//          r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
258//     then
259//                              3    2
260//          tan(x+y) = x + (T1*x + (x *(r+y)+y))
261//
262//  4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
263//          tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y))
264//                 = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y)))
265//
266// Set returnTan to 1 for tan; -1 for cot.  Anything else is illegal
267// and will cause incorrect results.
268//
269define T00 = 3.33333333333334091986e-01;
270define T01 = 1.33333333333201242699e-01;
271define T02 = 5.39682539762260521377e-02;
272define T03 = 2.18694882948595424599e-02;
273define T04 = 8.86323982359930005737e-03;
274define T05 = 3.59207910759131235356e-03;
275define T06 = 1.45620945432529025516e-03;
276define T07 = 5.88041240820264096874e-04;
277define T08 = 2.46463134818469906812e-04;
278define T09 = 7.81794442939557092300e-05;
279define T10 = 7.14072491382608190305e-05;
280define T11 = -1.85586374855275456654e-05;
281define T12 = 2.59073051863633712884e-05;
282
283function KernelTan(x, y, returnTan) {
284  var z;
285  var w;
286  var hx = %_DoubleHi(x);
287  var ix = hx & 0x7fffffff;
288
289  if (ix < 0x3e300000) {  // |x| < 2^-28
290    if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
291      // x == 0 && returnTan = -1
292      return 1 / MathAbs(x);
293    } else {
294      if (returnTan == 1) {
295        return x;
296      } else {
297        // Compute -1/(x + y) carefully
298        var w = x + y;
299        var z = %_ConstructDouble(%_DoubleHi(w), 0);
300        var v = y - (z - x);
301        var a = -1 / w;
302        var t = %_ConstructDouble(%_DoubleHi(a), 0);
303        var s = 1 + t * z;
304        return t + a * (s + t * v);
305      }
306    }
307  }
308  if (ix >= 0x3fe59428) {  // |x| > .6744
309    if (x < 0) {
310      x = -x;
311      y = -y;
312    }
313    z = PIO4 - x;
314    w = PIO4LO - y;
315    x = z + w;
316    y = 0;
317  }
318  z = x * x;
319  w = z * z;
320
321  // Break x^5 * (T1 + x^2*T2 + ...) into
322  // x^5 * (T1 + x^4*T3 + ... + x^20*T11) +
323  // x^5 * (x^2 * (T2 + x^4*T4 + ... + x^22*T12))
324  var r = T01 + w * (T03 + w * (T05 +
325                w * (T07 + w * (T09 + w * T11))));
326  var v = z * (T02 + w * (T04 + w * (T06 +
327                     w * (T08 + w * (T10 + w * T12)))));
328  var s = z * x;
329  r = y + z * (s * (r + v) + y);
330  r = r + T00 * s;
331  w = x + r;
332  if (ix >= 0x3fe59428) {
333    return (1 - ((hx >> 30) & 2)) *
334      (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r)));
335  }
336  if (returnTan == 1) {
337    return w;
338  } else {
339    z = %_ConstructDouble(%_DoubleHi(w), 0);
340    v = r - (z - x);
341    var a = -1 / w;
342    var t = %_ConstructDouble(%_DoubleHi(a), 0);
343    s = 1 + t * z;
344    return t + a * (s + t * v);
345  }
346}
347
348function MathSinSlow(x) {
349  REMPIO2(x);
350  var sign = 1 - (n & 2);
351  if (n & 1) {
352    RETURN_KERNELCOS(y0, y1, * sign);
353  } else {
354    RETURN_KERNELSIN(y0, y1, * sign);
355  }
356}
357
358function MathCosSlow(x) {
359  REMPIO2(x);
360  if (n & 1) {
361    var sign = (n & 2) - 1;
362    RETURN_KERNELSIN(y0, y1, * sign);
363  } else {
364    var sign = 1 - (n & 2);
365    RETURN_KERNELCOS(y0, y1, * sign);
366  }
367}
368
369// ECMA 262 - 15.8.2.16
370function MathSin(x) {
371  x = +x;  // Convert to number.
372  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
373    // |x| < pi/4, approximately.  No reduction needed.
374    RETURN_KERNELSIN(x, 0, /* empty */);
375  }
376  return +MathSinSlow(x);
377}
378
379// ECMA 262 - 15.8.2.7
380function MathCos(x) {
381  x = +x;  // Convert to number.
382  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
383    // |x| < pi/4, approximately.  No reduction needed.
384    RETURN_KERNELCOS(x, 0, /* empty */);
385  }
386  return +MathCosSlow(x);
387}
388
389// ECMA 262 - 15.8.2.18
390function MathTan(x) {
391  x = x * 1;  // Convert to number.
392  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
393    // |x| < pi/4, approximately.  No reduction needed.
394    return KernelTan(x, 0, 1);
395  }
396  REMPIO2(x);
397  return KernelTan(y0, y1, (n & 1) ? -1 : 1);
398}
399
400// ES6 draft 09-27-13, section 20.2.2.20.
401// Math.log1p
402//
403// Method :
404//   1. Argument Reduction: find k and f such that
405//                      1+x = 2^k * (1+f),
406//         where  sqrt(2)/2 < 1+f < sqrt(2) .
407//
408//      Note. If k=0, then f=x is exact. However, if k!=0, then f
409//      may not be representable exactly. In that case, a correction
410//      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
411//      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
412//      and add back the correction term c/u.
413//      (Note: when x > 2**53, one can simply return log(x))
414//
415//   2. Approximation of log1p(f).
416//      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
417//            = 2s + 2/3 s**3 + 2/5 s**5 + .....,
418//            = 2s + s*R
419//      We use a special Reme algorithm on [0,0.1716] to generate
420//      a polynomial of degree 14 to approximate R The maximum error
421//      of this polynomial approximation is bounded by 2**-58.45. In
422//      other words,
423//                      2      4      6      8      10      12      14
424//          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
425//      (the values of Lp1 to Lp7 are listed in the program)
426//      and
427//          |      2          14          |     -58.45
428//          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
429//          |                             |
430//      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
431//      In order to guarantee error in log below 1ulp, we compute log
432//      by
433//              log1p(f) = f - (hfsq - s*(hfsq+R)).
434//
435//      3. Finally, log1p(x) = k*ln2 + log1p(f).
436//                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
437//         Here ln2 is split into two floating point number:
438//                      ln2_hi + ln2_lo,
439//         where n*ln2_hi is always exact for |n| < 2000.
440//
441// Special cases:
442//      log1p(x) is NaN with signal if x < -1 (including -INF) ;
443//      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
444//      log1p(NaN) is that NaN with no signal.
445//
446// Accuracy:
447//      according to an error analysis, the error is always less than
448//      1 ulp (unit in the last place).
449//
450// Constants:
451//      Constants are found in fdlibm.cc. We assume the C++ compiler to convert
452//      from decimal to binary accurately enough to produce the intended values.
453//
454// Note: Assuming log() return accurate answer, the following
455//       algorithm can be used to compute log1p(x) to within a few ULP:
456//
457//              u = 1+x;
458//              if (u==1.0) return x ; else
459//                          return log(u)*(x/(u-1.0));
460//
461//       See HP-15C Advanced Functions Handbook, p.193.
462//
463define LN2_HI    = 6.93147180369123816490e-01;
464define LN2_LO    = 1.90821492927058770002e-10;
465define TWO_THIRD = 6.666666666666666666e-01;
466define LP1 = 6.666666666666735130e-01;
467define LP2 = 3.999999999940941908e-01;
468define LP3 = 2.857142874366239149e-01;
469define LP4 = 2.222219843214978396e-01;
470define LP5 = 1.818357216161805012e-01;
471define LP6 = 1.531383769920937332e-01;
472define LP7 = 1.479819860511658591e-01;
473
474// 2^54
475define TWO54 = 18014398509481984;
476
477function MathLog1p(x) {
478  x = x * 1;  // Convert to number.
479  var hx = %_DoubleHi(x);
480  var ax = hx & 0x7fffffff;
481  var k = 1;
482  var f = x;
483  var hu = 1;
484  var c = 0;
485  var u = x;
486
487  if (hx < 0x3fda827a) {
488    // x < 0.41422
489    if (ax >= 0x3ff00000) {  // |x| >= 1
490      if (x === -1) {
491        return -INFINITY;  // log1p(-1) = -inf
492      } else {
493        return NaN;  // log1p(x<-1) = NaN
494      }
495    } else if (ax < 0x3c900000)  {
496      // For |x| < 2^-54 we can return x.
497      return x;
498    } else if (ax < 0x3e200000) {
499      // For |x| < 2^-29 we can use a simple two-term Taylor series.
500      return x - x * x * 0.5;
501    }
502
503    if ((hx > 0) || (hx <= -0x402D413D)) {  // (int) 0xbfd2bec3 = -0x402d413d
504      // -.2929 < x < 0.41422
505      k = 0;
506    }
507  }
508
509  // Handle Infinity and NaN
510  if (hx >= 0x7ff00000) return x;
511
512  if (k !== 0) {
513    if (hx < 0x43400000) {
514      // x < 2^53
515      u = 1 + x;
516      hu = %_DoubleHi(u);
517      k = (hu >> 20) - 1023;
518      c = (k > 0) ? 1 - (u - x) : x - (u - 1);
519      c = c / u;
520    } else {
521      hu = %_DoubleHi(u);
522      k = (hu >> 20) - 1023;
523    }
524    hu = hu & 0xfffff;
525    if (hu < 0x6a09e) {
526      u = %_ConstructDouble(hu | 0x3ff00000, %_DoubleLo(u));  // Normalize u.
527    } else {
528      ++k;
529      u = %_ConstructDouble(hu | 0x3fe00000, %_DoubleLo(u));  // Normalize u/2.
530      hu = (0x00100000 - hu) >> 2;
531    }
532    f = u - 1;
533  }
534
535  var hfsq = 0.5 * f * f;
536  if (hu === 0) {
537    // |f| < 2^-20;
538    if (f === 0) {
539      if (k === 0) {
540        return 0.0;
541      } else {
542        return k * LN2_HI + (c + k * LN2_LO);
543      }
544    }
545    var R = hfsq * (1 - TWO_THIRD * f);
546    if (k === 0) {
547      return f - R;
548    } else {
549      return k * LN2_HI - ((R - (k * LN2_LO + c)) - f);
550    }
551  }
552
553  var s = f / (2 + f);
554  var z = s * s;
555  var R = z * (LP1 + z * (LP2 + z * (LP3 + z * (LP4 +
556          z * (LP5 + z * (LP6 + z * LP7))))));
557  if (k === 0) {
558    return f - (hfsq - s * (hfsq + R));
559  } else {
560    return k * LN2_HI - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f);
561  }
562}
563
564// ES6 draft 09-27-13, section 20.2.2.14.
565// Math.expm1
566// Returns exp(x)-1, the exponential of x minus 1.
567//
568// Method
569//   1. Argument reduction:
570//      Given x, find r and integer k such that
571//
572//               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
573//
574//      Here a correction term c will be computed to compensate
575//      the error in r when rounded to a floating-point number.
576//
577//   2. Approximating expm1(r) by a special rational function on
578//      the interval [0,0.34658]:
579//      Since
580//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
581//      we define R1(r*r) by
582//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
583//      That is,
584//          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
585//                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
586//                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
587//      We use a special Remes algorithm on [0,0.347] to generate
588//      a polynomial of degree 5 in r*r to approximate R1. The
589//      maximum error of this polynomial approximation is bounded
590//      by 2**-61. In other words,
591//          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
592//      where   Q1  =  -1.6666666666666567384E-2,
593//              Q2  =   3.9682539681370365873E-4,
594//              Q3  =  -9.9206344733435987357E-6,
595//              Q4  =   2.5051361420808517002E-7,
596//              Q5  =  -6.2843505682382617102E-9;
597//      (where z=r*r, and the values of Q1 to Q5 are listed below)
598//      with error bounded by
599//          |                  5           |     -61
600//          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
601//          |                              |
602//
603//      expm1(r) = exp(r)-1 is then computed by the following
604//      specific way which minimize the accumulation rounding error:
605//                             2     3
606//                            r     r    [ 3 - (R1 + R1*r/2)  ]
607//            expm1(r) = r + --- + --- * [--------------------]
608//                            2     2    [ 6 - r*(3 - R1*r/2) ]
609//
610//      To compensate the error in the argument reduction, we use
611//              expm1(r+c) = expm1(r) + c + expm1(r)*c
612//                         ~ expm1(r) + c + r*c
613//      Thus c+r*c will be added in as the correction terms for
614//      expm1(r+c). Now rearrange the term to avoid optimization
615//      screw up:
616//                      (      2                                    2 )
617//                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
618//       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
619//                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
620//                      (                                             )
621//
622//                 = r - E
623//   3. Scale back to obtain expm1(x):
624//      From step 1, we have
625//         expm1(x) = either 2^k*[expm1(r)+1] - 1
626//                  = or     2^k*[expm1(r) + (1-2^-k)]
627//   4. Implementation notes:
628//      (A). To save one multiplication, we scale the coefficient Qi
629//           to Qi*2^i, and replace z by (x^2)/2.
630//      (B). To achieve maximum accuracy, we compute expm1(x) by
631//        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
632//        (ii)  if k=0, return r-E
633//        (iii) if k=-1, return 0.5*(r-E)-0.5
634//        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
635//                     else          return  1.0+2.0*(r-E);
636//        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
637//        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
638//        (vii) return 2^k(1-((E+2^-k)-r))
639//
640// Special cases:
641//      expm1(INF) is INF, expm1(NaN) is NaN;
642//      expm1(-INF) is -1, and
643//      for finite argument, only expm1(0)=0 is exact.
644//
645// Accuracy:
646//      according to an error analysis, the error is always less than
647//      1 ulp (unit in the last place).
648//
649// Misc. info.
650//      For IEEE double
651//          if x > 7.09782712893383973096e+02 then expm1(x) overflow
652//
653define KEXPM1_OVERFLOW = 7.09782712893383973096e+02;
654define INVLN2          = 1.44269504088896338700;
655define EXPM1_1 = -3.33333333333331316428e-02;
656define EXPM1_2 = 1.58730158725481460165e-03;
657define EXPM1_3 = -7.93650757867487942473e-05;
658define EXPM1_4 = 4.00821782732936239552e-06;
659define EXPM1_5 = -2.01099218183624371326e-07;
660
661function MathExpm1(x) {
662  x = x * 1;  // Convert to number.
663  var y;
664  var hi;
665  var lo;
666  var k;
667  var t;
668  var c;
669
670  var hx = %_DoubleHi(x);
671  var xsb = hx & 0x80000000;     // Sign bit of x
672  var y = (xsb === 0) ? x : -x;  // y = |x|
673  hx &= 0x7fffffff;              // High word of |x|
674
675  // Filter out huge and non-finite argument
676  if (hx >= 0x4043687a) {     // if |x| ~=> 56 * ln2
677    if (hx >= 0x40862e42) {   // if |x| >= 709.78
678      if (hx >= 0x7ff00000) {
679        // expm1(inf) = inf; expm1(-inf) = -1; expm1(nan) = nan;
680        return (x === -INFINITY) ? -1 : x;
681      }
682      if (x > KEXPM1_OVERFLOW) return INFINITY;  // Overflow
683    }
684    if (xsb != 0) return -1;  // x < -56 * ln2, return -1.
685  }
686
687  // Argument reduction
688  if (hx > 0x3fd62e42) {    // if |x| > 0.5 * ln2
689    if (hx < 0x3ff0a2b2) {  // and |x| < 1.5 * ln2
690      if (xsb === 0) {
691        hi = x - LN2_HI;
692        lo = LN2_LO;
693        k = 1;
694      } else {
695        hi = x + LN2_HI;
696        lo = -LN2_LO;
697        k = -1;
698      }
699    } else {
700      k = (INVLN2 * x + ((xsb === 0) ? 0.5 : -0.5)) | 0;
701      t = k;
702      // t * ln2_hi is exact here.
703      hi = x - t * LN2_HI;
704      lo = t * LN2_LO;
705    }
706    x = hi - lo;
707    c = (hi - x) - lo;
708  } else if (hx < 0x3c900000)	{
709    // When |x| < 2^-54, we can return x.
710    return x;
711  } else {
712    // Fall through.
713    k = 0;
714  }
715
716  // x is now in primary range
717  var hfx = 0.5 * x;
718  var hxs = x * hfx;
719  var r1 = 1 + hxs * (EXPM1_1 + hxs * (EXPM1_2 + hxs *
720                     (EXPM1_3 + hxs * (EXPM1_4 + hxs * EXPM1_5))));
721  t = 3 - r1 * hfx;
722  var e = hxs * ((r1 - t) / (6 - x * t));
723  if (k === 0) {  // c is 0
724    return x - (x*e - hxs);
725  } else {
726    e = (x * (e - c) - c);
727    e -= hxs;
728    if (k === -1) return 0.5 * (x - e) - 0.5;
729    if (k === 1) {
730      if (x < -0.25) return -2 * (e - (x + 0.5));
731      return 1 + 2 * (x - e);
732    }
733
734    if (k <= -2 || k > 56) {
735      // suffice to return exp(x) + 1
736      y = 1 - (e - x);
737      // Add k to y's exponent
738      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
739      return y - 1;
740    }
741    if (k < 20) {
742      // t = 1 - 2^k
743      t = %_ConstructDouble(0x3ff00000 - (0x200000 >> k), 0);
744      y = t - (e - x);
745      // Add k to y's exponent
746      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
747    } else {
748      // t = 2^-k
749      t = %_ConstructDouble((0x3ff - k) << 20, 0);
750      y = x - (e + t);
751      y += 1;
752      // Add k to y's exponent
753      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
754    }
755  }
756  return y;
757}
758
759
760// ES6 draft 09-27-13, section 20.2.2.30.
761// Math.sinh
762// Method :
763// mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
764//      1. Replace x by |x| (sinh(-x) = -sinh(x)).
765//      2.
766//                                                  E + E/(E+1)
767//          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
768//                                                      2
769//
770//          22       <= x <= lnovft :  sinh(x) := exp(x)/2
771//          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
772//          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
773//
774// Special cases:
775//      sinh(x) is |x| if x is +Infinity, -Infinity, or NaN.
776//      only sinh(0)=0 is exact for finite x.
777//
778define KSINH_OVERFLOW = 710.4758600739439;
779define TWO_M28 = 3.725290298461914e-9;  // 2^-28, empty lower half
780define LOG_MAXD = 709.7822265625;  // 0x40862e42 00000000, empty lower half
781
782function MathSinh(x) {
783  x = x * 1;  // Convert to number.
784  var h = (x < 0) ? -0.5 : 0.5;
785  // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1))
786  var ax = MathAbs(x);
787  if (ax < 22) {
788    // For |x| < 2^-28, sinh(x) = x
789    if (ax < TWO_M28) return x;
790    var t = MathExpm1(ax);
791    if (ax < 1) return h * (2 * t - t * t / (t + 1));
792    return h * (t + t / (t + 1));
793  }
794  // |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
795  if (ax < LOG_MAXD) return h * MathExp(ax);
796  // |x| in [log(maxdouble), overflowthreshold]
797  // overflowthreshold = 710.4758600739426
798  if (ax <= KSINH_OVERFLOW) {
799    var w = MathExp(0.5 * ax);
800    var t = h * w;
801    return t * w;
802  }
803  // |x| > overflowthreshold or is NaN.
804  // Return Infinity of the appropriate sign or NaN.
805  return x * INFINITY;
806}
807
808
809// ES6 draft 09-27-13, section 20.2.2.12.
810// Math.cosh
811// Method :
812// mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
813//      1. Replace x by |x| (cosh(x) = cosh(-x)).
814//      2.
815//                                                      [ exp(x) - 1 ]^2
816//          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
817//                                                         2*exp(x)
818//
819//                                                 exp(x) + 1/exp(x)
820//          ln2/2    <= x <= 22     :  cosh(x) := -------------------
821//                                                        2
822//          22       <= x <= lnovft :  cosh(x) := exp(x)/2
823//          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
824//          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
825//
826// Special cases:
827//      cosh(x) is |x| if x is +INF, -INF, or NaN.
828//      only cosh(0)=1 is exact for finite x.
829//
830define KCOSH_OVERFLOW = 710.4758600739439;
831
832function MathCosh(x) {
833  x = x * 1;  // Convert to number.
834  var ix = %_DoubleHi(x) & 0x7fffffff;
835  // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|))
836  if (ix < 0x3fd62e43) {
837    var t = MathExpm1(MathAbs(x));
838    var w = 1 + t;
839    // For |x| < 2^-55, cosh(x) = 1
840    if (ix < 0x3c800000) return w;
841    return 1 + (t * t) / (w + w);
842  }
843  // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
844  if (ix < 0x40360000) {
845    var t = MathExp(MathAbs(x));
846    return 0.5 * t + 0.5 / t;
847  }
848  // |x| in [22, log(maxdouble)], return half*exp(|x|)
849  if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
850  // |x| in [log(maxdouble), overflowthreshold]
851  if (MathAbs(x) <= KCOSH_OVERFLOW) {
852    var w = MathExp(0.5 * MathAbs(x));
853    var t = 0.5 * w;
854    return t * w;
855  }
856  if (NUMBER_IS_NAN(x)) return x;
857  // |x| > overflowthreshold.
858  return INFINITY;
859}
860
861// ES6 draft 09-27-13, section 20.2.2.33.
862// Math.tanh(x)
863// Method :
864//                                    x    -x
865//                                   e  - e
866//     0. tanh(x) is defined to be -----------
867//                                    x    -x
868//                                   e  + e
869//     1. reduce x to non-negative by tanh(-x) = -tanh(x).
870//     2.  0      <= x <= 2**-55 : tanh(x) := x*(one+x)
871//                                             -t
872//         2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x)
873//                                            t + 2
874//                                                  2
875//         1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t = expm1(2x)
876//                                                t + 2
877//         22.0   <  x <= INF    : tanh(x) := 1.
878//
879// Special cases:
880//     tanh(NaN) is NaN;
881//     only tanh(0) = 0 is exact for finite argument.
882//
883
884define TWO_M55 = 2.77555756156289135105e-17;  // 2^-55, empty lower half
885
886function MathTanh(x) {
887  x = x * 1;  // Convert to number.
888  // x is Infinity or NaN
889  if (!NUMBER_IS_FINITE(x)) {
890    if (x > 0) return 1;
891    if (x < 0) return -1;
892    return x;
893  }
894
895  var ax = MathAbs(x);
896  var z;
897  // |x| < 22
898  if (ax < 22) {
899    if (ax < TWO_M55) {
900      // |x| < 2^-55, tanh(small) = small.
901      return x;
902    }
903    if (ax >= 1) {
904      // |x| >= 1
905      var t = MathExpm1(2 * ax);
906      z = 1 - 2 / (t + 2);
907    } else {
908      var t = MathExpm1(-2 * ax);
909      z = -t / (t + 2);
910    }
911  } else {
912    // |x| > 22, return +/- 1
913    z = 1;
914  }
915  return (x >= 0) ? z : -z;
916}
917
918// ES6 draft 09-27-13, section 20.2.2.21.
919// Return the base 10 logarithm of x
920//
921// Method :
922//      Let log10_2hi = leading 40 bits of log10(2) and
923//          log10_2lo = log10(2) - log10_2hi,
924//          ivln10   = 1/log(10) rounded.
925//      Then
926//              n = ilogb(x),
927//              if(n<0)  n = n+1;
928//              x = scalbn(x,-n);
929//              log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
930//
931// Note 1:
932//      To guarantee log10(10**n)=n, where 10**n is normal, the rounding
933//      mode must set to Round-to-Nearest.
934// Note 2:
935//      [1/log(10)] rounded to 53 bits has error .198 ulps;
936//      log10 is monotonic at all binary break points.
937//
938// Special cases:
939//      log10(x) is NaN if x < 0;
940//      log10(+INF) is +INF; log10(0) is -INF;
941//      log10(NaN) is that NaN;
942//      log10(10**N) = N  for N=0,1,...,22.
943//
944
945define IVLN10 = 4.34294481903251816668e-01;
946define LOG10_2HI = 3.01029995663611771306e-01;
947define LOG10_2LO = 3.69423907715893078616e-13;
948
949function MathLog10(x) {
950  x = x * 1;  // Convert to number.
951  var hx = %_DoubleHi(x);
952  var lx = %_DoubleLo(x);
953  var k = 0;
954
955  if (hx < 0x00100000) {
956    // x < 2^-1022
957    // log10(+/- 0) = -Infinity.
958    if (((hx & 0x7fffffff) | lx) === 0) return -INFINITY;
959    // log10 of negative number is NaN.
960    if (hx < 0) return NaN;
961    // Subnormal number. Scale up x.
962    k -= 54;
963    x *= TWO54;
964    hx = %_DoubleHi(x);
965    lx = %_DoubleLo(x);
966  }
967
968  // Infinity or NaN.
969  if (hx >= 0x7ff00000) return x;
970
971  k += (hx >> 20) - 1023;
972  var i = (k & 0x80000000) >>> 31;
973  hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
974  var y = k + i;
975  x = %_ConstructDouble(hx, lx);
976
977  var z = y * LOG10_2LO + IVLN10 * %_MathLogRT(x);
978  return z + y * LOG10_2HI;
979}
980
981
982// ES6 draft 09-27-13, section 20.2.2.22.
983// Return the base 2 logarithm of x
984//
985// fdlibm does not have an explicit log2 function, but fdlibm's pow
986// function does implement an accurate log2 function as part of the
987// pow implementation.  This extracts the core parts of that as a
988// separate log2 function.
989
990// Method:
991// Compute log2(x) in two pieces:
992// log2(x) = w1 + w2
993// where w1 has 53-24 = 29 bits of trailing zeroes.
994
995define DP_H = 5.84962487220764160156e-01;
996define DP_L = 1.35003920212974897128e-08;
997
998// Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
999define LOG2_1 = 5.99999999999994648725e-01;
1000define LOG2_2 = 4.28571428578550184252e-01;
1001define LOG2_3 = 3.33333329818377432918e-01;
1002define LOG2_4 = 2.72728123808534006489e-01;
1003define LOG2_5 = 2.30660745775561754067e-01;
1004define LOG2_6 = 2.06975017800338417784e-01;
1005
1006// cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
1007define CP = 9.61796693925975554329e-01;
1008define CP_H = 9.61796700954437255859e-01;
1009define CP_L = -7.02846165095275826516e-09;
1010// 2^53
1011define TWO53 = 9007199254740992;
1012
1013function MathLog2(x) {
1014  x = x * 1;  // Convert to number.
1015  var ax = MathAbs(x);
1016  var hx = %_DoubleHi(x);
1017  var lx = %_DoubleLo(x);
1018  var ix = hx & 0x7fffffff;
1019
1020  // Handle special cases.
1021  // log2(+/- 0) = -Infinity
1022  if ((ix | lx) == 0) return -INFINITY;
1023
1024  // log(x) = NaN, if x < 0
1025  if (hx < 0) return NaN;
1026
1027  // log2(Infinity) = Infinity, log2(NaN) = NaN
1028  if (ix >= 0x7ff00000) return x;
1029
1030  var n = 0;
1031
1032  // Take care of subnormal number.
1033  if (ix < 0x00100000) {
1034    ax *= TWO53;
1035    n -= 53;
1036    ix = %_DoubleHi(ax);
1037  }
1038
1039  n += (ix >> 20) - 0x3ff;
1040  var j = ix & 0x000fffff;
1041
1042  // Determine interval.
1043  ix = j | 0x3ff00000;  // normalize ix.
1044
1045  var bp = 1;
1046  var dp_h = 0;
1047  var dp_l = 0;
1048  if (j > 0x3988e) {  // |x| > sqrt(3/2)
1049    if (j < 0xbb67a) {  // |x| < sqrt(3)
1050      bp = 1.5;
1051      dp_h = DP_H;
1052      dp_l = DP_L;
1053    } else {
1054      n += 1;
1055      ix -= 0x00100000;
1056    }
1057  }
1058
1059  ax = %_ConstructDouble(ix, %_DoubleLo(ax));
1060
1061  // Compute ss = s_h + s_l = (x - 1)/(x+1) or (x - 1.5)/(x + 1.5)
1062  var u = ax - bp;
1063  var v = 1 / (ax + bp);
1064  var ss = u * v;
1065  var s_h = %_ConstructDouble(%_DoubleHi(ss), 0);
1066
1067  // t_h = ax + bp[k] High
1068  var t_h = %_ConstructDouble(%_DoubleHi(ax + bp), 0)
1069  var t_l = ax - (t_h - bp);
1070  var s_l = v * ((u - s_h * t_h) - s_h * t_l);
1071
1072  // Compute log2(ax)
1073  var s2 = ss * ss;
1074  var r = s2 * s2 * (LOG2_1 + s2 * (LOG2_2 + s2 * (LOG2_3 + s2 * (
1075                     LOG2_4 + s2 * (LOG2_5 + s2 * LOG2_6)))));
1076  r += s_l * (s_h + ss);
1077  s2  = s_h * s_h;
1078  t_h = %_ConstructDouble(%_DoubleHi(3.0 + s2 + r), 0);
1079  t_l = r - ((t_h - 3.0) - s2);
1080  // u + v = ss * (1 + ...)
1081  u = s_h * t_h;
1082  v = s_l * t_h + t_l * ss;
1083
1084  // 2 / (3 * log(2)) * (ss + ...)
1085  var p_h = %_ConstructDouble(%_DoubleHi(u + v), 0);
1086  var p_l = v - (p_h - u);
1087  var z_h = CP_H * p_h;
1088  var z_l = CP_L * p_h + p_l * CP + dp_l;
1089
1090  // log2(ax) = (ss + ...) * 2 / (3 * log(2)) = n + dp_h + z_h + z_l
1091  var t = n;
1092  var t1 = %_ConstructDouble(%_DoubleHi(((z_h + z_l) + dp_h) + t), 0);
1093  var t2 = z_l - (((t1 - t) - dp_h) - z_h);
1094
1095  // t1 + t2 = log2(ax), sum up because we do not care about extra precision.
1096  return t1 + t2;
1097}
1098
1099//-------------------------------------------------------------------
1100
1101utils.InstallFunctions(GlobalMath, DONT_ENUM, [
1102  "cos", MathCos,
1103  "sin", MathSin,
1104  "tan", MathTan,
1105  "sinh", MathSinh,
1106  "cosh", MathCosh,
1107  "tanh", MathTanh,
1108  "log10", MathLog10,
1109  "log2", MathLog2,
1110  "log1p", MathLog1p,
1111  "expm1", MathExpm1
1112]);
1113
1114%SetForceInlineFlag(MathSin);
1115%SetForceInlineFlag(MathCos);
1116
1117})
1118