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