| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 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 var rngstate; // Initialized to a Uint32Array during genesis. | |
| 6 | |
| 7 var $abs; | |
| 8 var $exp; | |
| 9 var $floor; | |
| 10 var $max; | |
| 11 var $min; | |
| 12 | |
| 13 (function() { | |
| 14 | |
| 15 "use strict"; | |
| 16 | |
| 17 %CheckIsBootstrapping(); | |
| 18 | |
| 19 var GlobalObject = global.Object; | |
| 20 | |
| 21 //------------------------------------------------------------------- | |
| 22 | |
| 23 // ECMA 262 - 15.8.2.1 | |
| 24 function MathAbs(x) { | |
| 25 x = +x; | |
| 26 return (x > 0) ? x : 0 - x; | |
| 27 } | |
| 28 | |
| 29 // ECMA 262 - 15.8.2.2 | |
| 30 function MathAcosJS(x) { | |
| 31 return %_MathAcos(+x); | |
| 32 } | |
| 33 | |
| 34 // ECMA 262 - 15.8.2.3 | |
| 35 function MathAsinJS(x) { | |
| 36 return %_MathAsin(+x); | |
| 37 } | |
| 38 | |
| 39 // ECMA 262 - 15.8.2.4 | |
| 40 function MathAtanJS(x) { | |
| 41 return %_MathAtan(+x); | |
| 42 } | |
| 43 | |
| 44 // ECMA 262 - 15.8.2.5 | |
| 45 // The naming of y and x matches the spec, as does the order in which | |
| 46 // ToNumber (valueOf) is called. | |
| 47 function MathAtan2JS(y, x) { | |
| 48 y = +y; | |
| 49 x = +x; | |
| 50 return %_MathAtan2(y, x); | |
| 51 } | |
| 52 | |
| 53 // ECMA 262 - 15.8.2.6 | |
| 54 function MathCeil(x) { | |
| 55 return -%_MathFloor(-x); | |
| 56 } | |
| 57 | |
| 58 // ECMA 262 - 15.8.2.8 | |
| 59 function MathExp(x) { | |
| 60 return %MathExpRT(TO_NUMBER_INLINE(x)); | |
| 61 } | |
| 62 | |
| 63 // ECMA 262 - 15.8.2.9 | |
| 64 function MathFloorJS(x) { | |
| 65 return %_MathFloor(+x); | |
| 66 } | |
| 67 | |
| 68 | |
| 69 // ECMA 262 - 15.8.2.11 | |
| 70 function MathMax(arg1, arg2) { // length == 2 | |
| 71 var length = %_ArgumentsLength(); | |
| 72 if (length == 2) { | |
| 73 arg1 = TO_NUMBER_INLINE(arg1); | |
| 74 arg2 = TO_NUMBER_INLINE(arg2); | |
| 75 if (arg2 > arg1) return arg2; | |
| 76 if (arg1 > arg2) return arg1; | |
| 77 if (arg1 == arg2) { | |
| 78 // Make sure -0 is considered less than +0. | |
| 79 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1; | |
| 80 } | |
| 81 // All comparisons failed, one of the arguments must be NaN. | |
| 82 return NAN; | |
| 83 } | |
| 84 var r = -INFINITY; | |
| 85 for (var i = 0; i < length; i++) { | |
| 86 var n = %_Arguments(i); | |
| 87 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | |
| 88 // Make sure +0 is considered greater than -0. | |
| 89 if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) { | |
| 90 r = n; | |
| 91 } | |
| 92 } | |
| 93 return r; | |
| 94 } | |
| 95 | |
| 96 // ECMA 262 - 15.8.2.12 | |
| 97 function MathMin(arg1, arg2) { // length == 2 | |
| 98 var length = %_ArgumentsLength(); | |
| 99 if (length == 2) { | |
| 100 arg1 = TO_NUMBER_INLINE(arg1); | |
| 101 arg2 = TO_NUMBER_INLINE(arg2); | |
| 102 if (arg2 > arg1) return arg1; | |
| 103 if (arg1 > arg2) return arg2; | |
| 104 if (arg1 == arg2) { | |
| 105 // Make sure -0 is considered less than +0. | |
| 106 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2; | |
| 107 } | |
| 108 // All comparisons failed, one of the arguments must be NaN. | |
| 109 return NAN; | |
| 110 } | |
| 111 var r = INFINITY; | |
| 112 for (var i = 0; i < length; i++) { | |
| 113 var n = %_Arguments(i); | |
| 114 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | |
| 115 // Make sure -0 is considered less than +0. | |
| 116 if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) { | |
| 117 r = n; | |
| 118 } | |
| 119 } | |
| 120 return r; | |
| 121 } | |
| 122 | |
| 123 // ECMA 262 - 15.8.2.13 | |
| 124 function MathPowJS(x, y) { | |
| 125 return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); | |
| 126 } | |
| 127 | |
| 128 // ECMA 262 - 15.8.2.14 | |
| 129 function MathRandom() { | |
| 130 var r0 = (MathImul(18030, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0; | |
| 131 rngstate[0] = r0; | |
| 132 var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0; | |
| 133 rngstate[1] = r1; | |
| 134 var x = ((r0 << 16) + (r1 & 0xFFFF)) | 0; | |
| 135 // Division by 0x100000000 through multiplication by reciprocal. | |
| 136 return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10; | |
| 137 } | |
| 138 | |
| 139 // ECMA 262 - 15.8.2.15 | |
| 140 function MathRound(x) { | |
| 141 return %RoundNumber(TO_NUMBER_INLINE(x)); | |
| 142 } | |
| 143 | |
| 144 // ECMA 262 - 15.8.2.17 | |
| 145 function MathSqrtJS(x) { | |
| 146 return %_MathSqrt(+x); | |
| 147 } | |
| 148 | |
| 149 // Non-standard extension. | |
| 150 function MathImul(x, y) { | |
| 151 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); | |
| 152 } | |
| 153 | |
| 154 // ES6 draft 09-27-13, section 20.2.2.28. | |
| 155 function MathSign(x) { | |
| 156 x = +x; | |
| 157 if (x > 0) return 1; | |
| 158 if (x < 0) return -1; | |
| 159 // -0, 0 or NaN. | |
| 160 return x; | |
| 161 } | |
| 162 | |
| 163 // ES6 draft 09-27-13, section 20.2.2.34. | |
| 164 function MathTrunc(x) { | |
| 165 x = +x; | |
| 166 if (x > 0) return %_MathFloor(x); | |
| 167 if (x < 0) return -%_MathFloor(-x); | |
| 168 // -0, 0 or NaN. | |
| 169 return x; | |
| 170 } | |
| 171 | |
| 172 // ES6 draft 09-27-13, section 20.2.2.33. | |
| 173 function MathTanh(x) { | |
| 174 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
| 175 // Idempotent for +/-0. | |
| 176 if (x === 0) return x; | |
| 177 // Returns +/-1 for +/-Infinity. | |
| 178 if (!NUMBER_IS_FINITE(x)) return MathSign(x); | |
| 179 var exp1 = MathExp(x); | |
| 180 var exp2 = MathExp(-x); | |
| 181 return (exp1 - exp2) / (exp1 + exp2); | |
| 182 } | |
| 183 | |
| 184 // ES6 draft 09-27-13, section 20.2.2.5. | |
| 185 function MathAsinh(x) { | |
| 186 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
| 187 // Idempotent for NaN, +/-0 and +/-Infinity. | |
| 188 if (x === 0 || !NUMBER_IS_FINITE(x)) return x; | |
| 189 if (x > 0) return $log(x + %_MathSqrt(x * x + 1)); | |
| 190 // This is to prevent numerical errors caused by large negative x. | |
| 191 return -$log(-x + %_MathSqrt(x * x + 1)); | |
| 192 } | |
| 193 | |
| 194 // ES6 draft 09-27-13, section 20.2.2.3. | |
| 195 function MathAcosh(x) { | |
| 196 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
| 197 if (x < 1) return NAN; | |
| 198 // Idempotent for NaN and +Infinity. | |
| 199 if (!NUMBER_IS_FINITE(x)) return x; | |
| 200 return $log(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1)); | |
| 201 } | |
| 202 | |
| 203 // ES6 draft 09-27-13, section 20.2.2.7. | |
| 204 function MathAtanh(x) { | |
| 205 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
| 206 // Idempotent for +/-0. | |
| 207 if (x === 0) return x; | |
| 208 // Returns NaN for NaN and +/- Infinity. | |
| 209 if (!NUMBER_IS_FINITE(x)) return NAN; | |
| 210 return 0.5 * $log((1 + x) / (1 - x)); | |
| 211 } | |
| 212 | |
| 213 // ES6 draft 09-27-13, section 20.2.2.17. | |
| 214 function MathHypot(x, y) { // Function length is 2. | |
| 215 // We may want to introduce fast paths for two arguments and when | |
| 216 // normalization to avoid overflow is not necessary. For now, we | |
| 217 // simply assume the general case. | |
| 218 var length = %_ArgumentsLength(); | |
| 219 var args = new InternalArray(length); | |
| 220 var max = 0; | |
| 221 for (var i = 0; i < length; i++) { | |
| 222 var n = %_Arguments(i); | |
| 223 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | |
| 224 if (n === INFINITY || n === -INFINITY) return INFINITY; | |
| 225 n = MathAbs(n); | |
| 226 if (n > max) max = n; | |
| 227 args[i] = n; | |
| 228 } | |
| 229 | |
| 230 // Kahan summation to avoid rounding errors. | |
| 231 // Normalize the numbers to the largest one to avoid overflow. | |
| 232 if (max === 0) max = 1; | |
| 233 var sum = 0; | |
| 234 var compensation = 0; | |
| 235 for (var i = 0; i < length; i++) { | |
| 236 var n = args[i] / max; | |
| 237 var summand = n * n - compensation; | |
| 238 var preliminary = sum + summand; | |
| 239 compensation = (preliminary - sum) - summand; | |
| 240 sum = preliminary; | |
| 241 } | |
| 242 return %_MathSqrt(sum) * max; | |
| 243 } | |
| 244 | |
| 245 // ES6 draft 09-27-13, section 20.2.2.16. | |
| 246 function MathFroundJS(x) { | |
| 247 return %MathFround(TO_NUMBER_INLINE(x)); | |
| 248 } | |
| 249 | |
| 250 // ES6 draft 07-18-14, section 20.2.2.11 | |
| 251 function MathClz32JS(x) { | |
| 252 return %_MathClz32(x >>> 0); | |
| 253 } | |
| 254 | |
| 255 // ES6 draft 09-27-13, section 20.2.2.9. | |
| 256 // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm | |
| 257 // Using initial approximation adapted from Kahan's cbrt and 4 iterations | |
| 258 // of Newton's method. | |
| 259 function MathCbrt(x) { | |
| 260 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
| 261 if (x == 0 || !NUMBER_IS_FINITE(x)) return x; | |
| 262 return x >= 0 ? CubeRoot(x) : -CubeRoot(-x); | |
| 263 } | |
| 264 | |
| 265 macro NEWTON_ITERATION_CBRT(x, approx) | |
| 266 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx); | |
| 267 endmacro | |
| 268 | |
| 269 function CubeRoot(x) { | |
| 270 var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893; | |
| 271 var approx = %_ConstructDouble(approx_hi, 0); | |
| 272 approx = NEWTON_ITERATION_CBRT(x, approx); | |
| 273 approx = NEWTON_ITERATION_CBRT(x, approx); | |
| 274 approx = NEWTON_ITERATION_CBRT(x, approx); | |
| 275 return NEWTON_ITERATION_CBRT(x, approx); | |
| 276 } | |
| 277 | |
| 278 // ------------------------------------------------------------------- | |
| 279 | |
| 280 // Instance class name can only be set on functions. That is the only | |
| 281 // purpose for MathConstructor. | |
| 282 function MathConstructor() {} | |
| 283 | |
| 284 var Math = new MathConstructor(); | |
| 285 | |
| 286 %InternalSetPrototype(Math, GlobalObject.prototype); | |
| 287 %AddNamedProperty(global, "Math", Math, DONT_ENUM); | |
| 288 %FunctionSetInstanceClassName(MathConstructor, 'Math'); | |
| 289 | |
| 290 %AddNamedProperty(Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM); | |
| 291 | |
| 292 // Set up math constants. | |
| 293 InstallConstants(Math, [ | |
| 294 // ECMA-262, section 15.8.1.1. | |
| 295 "E", 2.7182818284590452354, | |
| 296 // ECMA-262, section 15.8.1.2. | |
| 297 "LN10", 2.302585092994046, | |
| 298 // ECMA-262, section 15.8.1.3. | |
| 299 "LN2", 0.6931471805599453, | |
| 300 // ECMA-262, section 15.8.1.4. | |
| 301 "LOG2E", 1.4426950408889634, | |
| 302 "LOG10E", 0.4342944819032518, | |
| 303 "PI", 3.1415926535897932, | |
| 304 "SQRT1_2", 0.7071067811865476, | |
| 305 "SQRT2", 1.4142135623730951 | |
| 306 ]); | |
| 307 | |
| 308 // Set up non-enumerable functions of the Math object and | |
| 309 // set their names. | |
| 310 InstallFunctions(Math, DONT_ENUM, [ | |
| 311 "random", MathRandom, | |
| 312 "abs", MathAbs, | |
| 313 "acos", MathAcosJS, | |
| 314 "asin", MathAsinJS, | |
| 315 "atan", MathAtanJS, | |
| 316 "ceil", MathCeil, | |
| 317 "exp", MathExp, | |
| 318 "floor", MathFloorJS, | |
| 319 "round", MathRound, | |
| 320 "sqrt", MathSqrtJS, | |
| 321 "atan2", MathAtan2JS, | |
| 322 "pow", MathPowJS, | |
| 323 "max", MathMax, | |
| 324 "min", MathMin, | |
| 325 "imul", MathImul, | |
| 326 "sign", MathSign, | |
| 327 "trunc", MathTrunc, | |
| 328 "tanh", MathTanh, | |
| 329 "asinh", MathAsinh, | |
| 330 "acosh", MathAcosh, | |
| 331 "atanh", MathAtanh, | |
| 332 "hypot", MathHypot, | |
| 333 "fround", MathFroundJS, | |
| 334 "clz32", MathClz32JS, | |
| 335 "cbrt", MathCbrt | |
| 336 ]); | |
| 337 | |
| 338 %SetInlineBuiltinFlag(MathAbs); | |
| 339 %SetInlineBuiltinFlag(MathAcosJS); | |
| 340 %SetInlineBuiltinFlag(MathAsinJS); | |
| 341 %SetInlineBuiltinFlag(MathAtanJS); | |
| 342 %SetInlineBuiltinFlag(MathAtan2JS); | |
| 343 %SetInlineBuiltinFlag(MathCeil); | |
| 344 %SetInlineBuiltinFlag(MathClz32JS); | |
| 345 %SetInlineBuiltinFlag(MathFloorJS); | |
| 346 %SetInlineBuiltinFlag(MathRandom); | |
| 347 %SetInlineBuiltinFlag(MathSign); | |
| 348 %SetInlineBuiltinFlag(MathSqrtJS); | |
| 349 %SetInlineBuiltinFlag(MathTrunc); | |
| 350 | |
| 351 // Expose to the global scope. | |
| 352 $abs = MathAbs; | |
| 353 $exp = MathExp; | |
| 354 $floor = MathFloorJS; | |
| 355 $max = MathMax; | |
| 356 $min = MathMin; | |
| 357 | |
| 358 })(); | |
| OLD | NEW |