Home | History | Annotate | Download | only in fdlibm
      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 (a] 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 
     31 var GlobalFloat64Array = global.Float64Array;
     32 var GlobalMath = global.Math;
     33 var MathAbs;
     34 var MathExp;
     35 var NaN = %GetRootNaN();
     36 var rempio2result;
     37 
     38 utils.Import(function(from) {
     39   MathAbs = from.MathAbs;
     40   MathExp = from.MathExp;
     41 });
     42 
     43 utils.CreateDoubleResultArray = function(global) {
     44   rempio2result = new GlobalFloat64Array(2);
     45 };
     46 
     47 // -------------------------------------------------------------------
     48 
     49 define INVPIO2 = 6.36619772367581382433e-01;
     50 define PIO2_1  = 1.57079632673412561417;
     51 define PIO2_1T = 6.07710050650619224932e-11;
     52 define PIO2_2  = 6.07710050630396597660e-11;
     53 define PIO2_2T = 2.02226624879595063154e-21;
     54 define PIO2_3  = 2.02226624871116645580e-21;
     55 define PIO2_3T = 8.47842766036889956997e-32;
     56 define PIO4    = 7.85398163397448278999e-01;
     57 define 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 
     63 macro 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   }
    134 endmacro
    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 //
    162 define S1 = -1.66666666666666324348e-01;
    163 define S2 = 8.33333333332248946124e-03;
    164 define S3 = -1.98412698298579493134e-04;
    165 define S4 = 2.75573137070700676789e-06;
    166 define S5 = -2.50507602534068634195e-08;
    167 define S6 = 1.58969099521155010221e-10;
    168 
    169 macro 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;
    174 endmacro
    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 //
    208 define C1 = 4.16666666666666019037e-02;
    209 define C2 = -1.38888888888741095749e-03;
    210 define C3 = 2.48015872894767294178e-05;
    211 define C4 = -2.75573143513906633035e-07;
    212 define C5 = 2.08757232129817482790e-09;
    213 define C6 = -1.13596475577881948265e-11;
    214 
    215 macro 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   }
    231 endmacro
    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 //
    269 define T00 = 3.33333333333334091986e-01;
    270 define T01 = 1.33333333333201242699e-01;
    271 define T02 = 5.39682539762260521377e-02;
    272 define T03 = 2.18694882948595424599e-02;
    273 define T04 = 8.86323982359930005737e-03;
    274 define T05 = 3.59207910759131235356e-03;
    275 define T06 = 1.45620945432529025516e-03;
    276 define T07 = 5.88041240820264096874e-04;
    277 define T08 = 2.46463134818469906812e-04;
    278 define T09 = 7.81794442939557092300e-05;
    279 define T10 = 7.14072491382608190305e-05;
    280 define T11 = -1.85586374855275456654e-05;
    281 define T12 = 2.59073051863633712884e-05;
    282 
    283 function 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 
    348 function 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 
    358 function 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
    370 function 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
    380 function 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
    390 function 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 //
    463 define LN2_HI    = 6.93147180369123816490e-01;
    464 define LN2_LO    = 1.90821492927058770002e-10;
    465 define TWO_THIRD = 6.666666666666666666e-01;
    466 define LP1 = 6.666666666666735130e-01;
    467 define LP2 = 3.999999999940941908e-01;
    468 define LP3 = 2.857142874366239149e-01;
    469 define LP4 = 2.222219843214978396e-01;
    470 define LP5 = 1.818357216161805012e-01;
    471 define LP6 = 1.531383769920937332e-01;
    472 define LP7 = 1.479819860511658591e-01;
    473 
    474 // 2^54
    475 define TWO54 = 18014398509481984;
    476 
    477 function 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 //
    653 define KEXPM1_OVERFLOW = 7.09782712893383973096e+02;
    654 define INVLN2          = 1.44269504088896338700;
    655 define EXPM1_1 = -3.33333333333331316428e-02;
    656 define EXPM1_2 = 1.58730158725481460165e-03;
    657 define EXPM1_3 = -7.93650757867487942473e-05;
    658 define EXPM1_4 = 4.00821782732936239552e-06;
    659 define EXPM1_5 = -2.01099218183624371326e-07;
    660 
    661 function 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 //
    778 define KSINH_OVERFLOW = 710.4758600739439;
    779 define TWO_M28 = 3.725290298461914e-9;  // 2^-28, empty lower half
    780 define LOG_MAXD = 709.7822265625;  // 0x40862e42 00000000, empty lower half
    781 
    782 function 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 //
    830 define KCOSH_OVERFLOW = 710.4758600739439;
    831 
    832 function 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 
    884 define TWO_M55 = 2.77555756156289135105e-17;  // 2^-55, empty lower half
    885 
    886 function 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 
    945 define IVLN10 = 4.34294481903251816668e-01;
    946 define LOG10_2HI = 3.01029995663611771306e-01;
    947 define LOG10_2LO = 3.69423907715893078616e-13;
    948 
    949 function 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 
    995 define DP_H = 5.84962487220764160156e-01;
    996 define DP_L = 1.35003920212974897128e-08;
    997 
    998 // Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
    999 define LOG2_1 = 5.99999999999994648725e-01;
   1000 define LOG2_2 = 4.28571428578550184252e-01;
   1001 define LOG2_3 = 3.33333329818377432918e-01;
   1002 define LOG2_4 = 2.72728123808534006489e-01;
   1003 define LOG2_5 = 2.30660745775561754067e-01;
   1004 define LOG2_6 = 2.06975017800338417784e-01;
   1005 
   1006 // cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
   1007 define CP = 9.61796693925975554329e-01;
   1008 define CP_H = 9.61796700954437255859e-01;
   1009 define CP_L = -7.02846165095275826516e-09;
   1010 // 2^53
   1011 define TWO53 = 9007199254740992; 
   1012 
   1013 function 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 
   1101 utils.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