Home | History | Annotate | Download | only in src
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 // ES6 draft 09-27-13, section 20.2.2.28.
      8 function MathSign(x) {
      9   x = TO_NUMBER_INLINE(x);
     10   if (x > 0) return 1;
     11   if (x < 0) return -1;
     12   if (x === 0) return x;
     13   return NAN;
     14 }
     15 
     16 
     17 // ES6 draft 09-27-13, section 20.2.2.34.
     18 function MathTrunc(x) {
     19   x = TO_NUMBER_INLINE(x);
     20   if (x > 0) return MathFloor(x);
     21   if (x < 0) return MathCeil(x);
     22   if (x === 0) return x;
     23   return NAN;
     24 }
     25 
     26 
     27 // ES6 draft 09-27-13, section 20.2.2.30.
     28 function MathSinh(x) {
     29   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     30   // Idempotent for NaN, +/-0 and +/-Infinity.
     31   if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
     32   return (MathExp(x) - MathExp(-x)) / 2;
     33 }
     34 
     35 
     36 // ES6 draft 09-27-13, section 20.2.2.12.
     37 function MathCosh(x) {
     38   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     39   if (!NUMBER_IS_FINITE(x)) return MathAbs(x);
     40   return (MathExp(x) + MathExp(-x)) / 2;
     41 }
     42 
     43 
     44 // ES6 draft 09-27-13, section 20.2.2.33.
     45 function MathTanh(x) {
     46   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     47   // Idempotent for +/-0.
     48   if (x === 0) return x;
     49   // Returns +/-1 for +/-Infinity.
     50   if (!NUMBER_IS_FINITE(x)) return MathSign(x);
     51   var exp1 = MathExp(x);
     52   var exp2 = MathExp(-x);
     53   return (exp1 - exp2) / (exp1 + exp2);
     54 }
     55 
     56 
     57 // ES6 draft 09-27-13, section 20.2.2.5.
     58 function MathAsinh(x) {
     59   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     60   // Idempotent for NaN, +/-0 and +/-Infinity.
     61   if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
     62   if (x > 0) return MathLog(x + MathSqrt(x * x + 1));
     63   // This is to prevent numerical errors caused by large negative x.
     64   return -MathLog(-x + MathSqrt(x * x + 1));
     65 }
     66 
     67 
     68 // ES6 draft 09-27-13, section 20.2.2.3.
     69 function MathAcosh(x) {
     70   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     71   if (x < 1) return NAN;
     72   // Idempotent for NaN and +Infinity.
     73   if (!NUMBER_IS_FINITE(x)) return x;
     74   return MathLog(x + MathSqrt(x + 1) * MathSqrt(x - 1));
     75 }
     76 
     77 
     78 // ES6 draft 09-27-13, section 20.2.2.7.
     79 function MathAtanh(x) {
     80   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
     81   // Idempotent for +/-0.
     82   if (x === 0) return x;
     83   // Returns NaN for NaN and +/- Infinity.
     84   if (!NUMBER_IS_FINITE(x)) return NAN;
     85   return 0.5 * MathLog((1 + x) / (1 - x));
     86 }
     87 
     88 
     89 // ES6 draft 09-27-13, section 20.2.2.21.
     90 function MathLog10(x) {
     91   return MathLog(x) * 0.434294481903251828;  // log10(x) = log(x)/log(10).
     92 }
     93 
     94 
     95 // ES6 draft 09-27-13, section 20.2.2.22.
     96 function MathLog2(x) {
     97   return MathLog(x) * 1.442695040888963407;  // log2(x) = log(x)/log(2).
     98 }
     99 
    100 
    101 // ES6 draft 09-27-13, section 20.2.2.17.
    102 function MathHypot(x, y) {  // Function length is 2.
    103   // We may want to introduce fast paths for two arguments and when
    104   // normalization to avoid overflow is not necessary.  For now, we
    105   // simply assume the general case.
    106   var length = %_ArgumentsLength();
    107   var args = new InternalArray(length);
    108   var max = 0;
    109   for (var i = 0; i < length; i++) {
    110     var n = %_Arguments(i);
    111     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
    112     if (n === INFINITY || n === -INFINITY) return INFINITY;
    113     n = MathAbs(n);
    114     if (n > max) max = n;
    115     args[i] = n;
    116   }
    117 
    118   // Kahan summation to avoid rounding errors.
    119   // Normalize the numbers to the largest one to avoid overflow.
    120   if (max === 0) max = 1;
    121   var sum = 0;
    122   var compensation = 0;
    123   for (var i = 0; i < length; i++) {
    124     var n = args[i] / max;
    125     var summand = n * n - compensation;
    126     var preliminary = sum + summand;
    127     compensation = (preliminary - sum) - summand;
    128     sum = preliminary;
    129   }
    130   return MathSqrt(sum) * max;
    131 }
    132 
    133 
    134 // ES6 draft 09-27-13, section 20.2.2.16.
    135 function MathFroundJS(x) {
    136   return %MathFround(TO_NUMBER_INLINE(x));
    137 }
    138 
    139 
    140 function MathClz32(x) {
    141   x = ToUint32(TO_NUMBER_INLINE(x));
    142   if (x == 0) return 32;
    143   var result = 0;
    144   // Binary search.
    145   if ((x & 0xFFFF0000) === 0) { x <<= 16; result += 16; };
    146   if ((x & 0xFF000000) === 0) { x <<=  8; result +=  8; };
    147   if ((x & 0xF0000000) === 0) { x <<=  4; result +=  4; };
    148   if ((x & 0xC0000000) === 0) { x <<=  2; result +=  2; };
    149   if ((x & 0x80000000) === 0) { x <<=  1; result +=  1; };
    150   return result;
    151 }
    152 
    153 
    154 // ES6 draft 09-27-13, section 20.2.2.9.
    155 // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm
    156 // Using initial approximation adapted from Kahan's cbrt and 4 iterations
    157 // of Newton's method.
    158 function MathCbrt(x) {
    159   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
    160   if (x == 0 || !NUMBER_IS_FINITE(x)) return x;
    161   return x >= 0 ? CubeRoot(x) : -CubeRoot(-x);
    162 }
    163 
    164 macro NEWTON_ITERATION_CBRT(x, approx)
    165   (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
    166 endmacro
    167 
    168 function CubeRoot(x) {
    169   var approx_hi = MathFloor(%_DoubleHi(x) / 3) + 0x2A9F7893;
    170   var approx = %_ConstructDouble(approx_hi, 0);
    171   approx = NEWTON_ITERATION_CBRT(x, approx);
    172   approx = NEWTON_ITERATION_CBRT(x, approx);
    173   approx = NEWTON_ITERATION_CBRT(x, approx);
    174   return NEWTON_ITERATION_CBRT(x, approx);
    175 }
    176 
    177 
    178 
    179 // ES6 draft 09-27-13, section 20.2.2.14.
    180 // Use Taylor series to approximate.
    181 // exp(x) - 1 at 0 == -1 + exp(0) + exp'(0)*x/1! + exp''(0)*x^2/2! + ...
    182 //                 == x/1! + x^2/2! + x^3/3! + ...
    183 // The closer x is to 0, the fewer terms are required.
    184 function MathExpm1(x) {
    185   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
    186   var xabs = MathAbs(x);
    187   if (xabs < 2E-7) {
    188     return x * (1 + x * (1/2));
    189   } else if (xabs < 6E-5) {
    190     return x * (1 + x * (1/2 + x * (1/6)));
    191   } else if (xabs < 2E-2) {
    192     return x * (1 + x * (1/2 + x * (1/6 +
    193            x * (1/24 + x * (1/120 + x * (1/720))))));
    194   } else {  // Use regular exp if not close enough to 0.
    195     return MathExp(x) - 1;
    196   }
    197 }
    198 
    199 
    200 // ES6 draft 09-27-13, section 20.2.2.20.
    201 // Use Taylor series to approximate. With y = x + 1;
    202 // log(y) at 1 == log(1) + log'(1)(y-1)/1! + log''(1)(y-1)^2/2! + ...
    203 //             == 0 + x - x^2/2 + x^3/3 ...
    204 // The closer x is to 0, the fewer terms are required.
    205 function MathLog1p(x) {
    206   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
    207   var xabs = MathAbs(x);
    208   if (xabs < 1E-7) {
    209     return x * (1 - x * (1/2));
    210   } else if (xabs < 3E-5) {
    211     return x * (1 - x * (1/2 - x * (1/3)));
    212   } else if (xabs < 7E-3) {
    213     return x * (1 - x * (1/2 - x * (1/3 - x * (1/4 -
    214            x * (1/5 - x * (1/6 - x * (1/7)))))));
    215   } else {  // Use regular log if not close enough to 0.
    216     return MathLog(1 + x);
    217   }
    218 }
    219 
    220 
    221 function ExtendMath() {
    222   %CheckIsBootstrapping();
    223 
    224   // Set up the non-enumerable functions on the Math object.
    225   InstallFunctions($Math, DONT_ENUM, $Array(
    226     "sign", MathSign,
    227     "trunc", MathTrunc,
    228     "sinh", MathSinh,
    229     "cosh", MathCosh,
    230     "tanh", MathTanh,
    231     "asinh", MathAsinh,
    232     "acosh", MathAcosh,
    233     "atanh", MathAtanh,
    234     "log10", MathLog10,
    235     "log2", MathLog2,
    236     "hypot", MathHypot,
    237     "fround", MathFroundJS,
    238     "clz32", MathClz32,
    239     "cbrt", MathCbrt,
    240     "log1p", MathLog1p,
    241     "expm1", MathExpm1
    242   ));
    243 }
    244 
    245 
    246 ExtendMath();
    247