blob: a5e789f38a59d56083c82338aca4cd59bbb7aee0 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019// rempio2result is used as a container for return values of %RemPiO2. It is
20// initialized to a two-element Float64Array during genesis.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022(function(global, utils) {
23
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024"use strict";
25
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026%CheckIsBootstrapping();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028// -------------------------------------------------------------------
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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058
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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063macro 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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 n = %RemPiO2(X, rempio2result);
131 y0 = rempio2result[0];
132 y1 = rempio2result[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133 }
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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162define 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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168
169macro RETURN_KERNELSIN(X, Y, SIGN)
170 var z = X * X;
171 var v = z * X;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 var r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6)));
173 return (X - ((z * (0.5 * Y - v * r) - Y) - v * S1)) SIGN;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174endmacro
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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208define 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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214
215macro RETURN_KERNELCOS(X, Y, SIGN)
216 var ix = %_DoubleHi(X) & 0x7fffffff;
217 var z = X * X;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 var r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6)))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269define 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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282
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))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 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)))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 var s = z * x;
329 r = y + z * (s * (r + v) + y);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330 r = r + T00 * s;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 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) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 x = +x; // Convert to number.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
373 // |x| < pi/4, approximately. No reduction needed.
374 RETURN_KERNELSIN(x, 0, /* empty */);
375 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 return +MathSinSlow(x);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000377}
378
379// ECMA 262 - 15.8.2.7
380function MathCos(x) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000381 x = +x; // Convert to number.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
383 // |x| < pi/4, approximately. No reduction needed.
384 RETURN_KERNELCOS(x, 0, /* empty */);
385 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386 return +MathCosSlow(x);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387}
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//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400403// Method :
404// 1. Argument Reduction: find k and f such that
405// 1+x = 2^k * (1+f),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419// We use a special Reme algorithm on [0,0.1716] to generate
420// a polynomial of degree 14 to approximate R The maximum error
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400428// | Lp1*s +...+Lp7*s - R(z) | <= 2
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429// | |
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//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400435// 3. Finally, log1p(x) = k*ln2 + log1p(f).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436// = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437// Here ln2 is split into two floating point number:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438// ln2_hi + ln2_lo,
439// where n*ln2_hi is always exact for |n| < 2000.
440//
441// Special cases:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400442// log1p(x) is NaN with signal if x < -1 (including -INF) ;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443// 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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463define 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400474// 2^54
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475define TWO54 = 18014398509481984;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476
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 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 return NaN; // log1p(x<-1) = NaN
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 }
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 // Handle Infinity and NaN
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000510 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400553 var s = f / (2 + f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 var z = s * s;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 var R = z * (LP1 + z * (LP2 + z * (LP3 + z * (LP4 +
556 z * (LP5 + z * (LP6 + z * LP7))))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557 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//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400572// x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574// Here a correction term c will be computed to compensate
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575// 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 + ...
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400587// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400600// | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601// | |
602//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400603// expm1(r) = exp(r)-1 is then computed by the following
604// specific way which minimize the accumulation rounding error:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400611// expm1(r+c) = expm1(r) + c + expm1(r)*c
612// ~ expm1(r) + c + r*c
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613// Thus c+r*c will be added in as the correction terms for
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400614// expm1(r+c). Now rearrange the term to avoid optimization
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000615// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400638// (vii) return 2^k(1-((E+2^-k)-r))
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639//
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.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400650// For IEEE double
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651// if x > 7.09782712893383973096e+02 then expm1(x) overflow
652//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000653define 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;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000660
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;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400669
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000670 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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719 var r1 = 1 + hxs * (EXPM1_1 + hxs * (EXPM1_2 + hxs *
720 (EXPM1_3 + hxs * (EXPM1_4 + hxs * EXPM1_5))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 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//
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400770// 22 <= x <= lnovft : sinh(x) := exp(x)/2
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000771// 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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778define 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781
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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400811// Method :
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812// mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400813// 1. Replace x by |x| (cosh(x) = cosh(-x)).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000814// 2.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400815// [ exp(x) - 1 ]^2
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822// 22 <= x <= lnovft : cosh(x) := exp(x)/2
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000823// 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//
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830define KCOSH_OVERFLOW = 710.4758600739439;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831
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}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400860
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000861// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400918// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945define IVLN10 = 4.34294481903251816668e-01;
946define LOG10_2HI = 3.01029995663611771306e-01;
947define LOG10_2LO = 3.69423907715893078616e-13;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400948
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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 if (hx < 0) return NaN;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400961 // 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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972 var i = (k & 0x80000000) >>> 31;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400973 hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000974 var y = k + i;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400975 x = %_ConstructDouble(hx, lx);
976
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977 var z = y * LOG10_2LO + IVLN10 * %_MathLogRT(x);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400978 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000995define DP_H = 5.84962487220764160156e-01;
996define DP_L = 1.35003920212974897128e-08;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400997
998// Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000999define 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;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001005
1006// cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001007define CP = 9.61796693925975554329e-01;
1008define CP_H = 9.61796700954437255859e-01;
1009define CP_L = -7.02846165095275826516e-09;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001010// 2^53
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001011define TWO53 = 9007199254740992;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001012
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001025 if (hx < 0) return NaN;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001026
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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 var r = s2 * s2 * (LOG2_1 + s2 * (LOG2_2 + s2 * (LOG2_3 + s2 * (
1075 LOG2_4 + s2 * (LOG2_5 + s2 * LOG2_6)))));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001076 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 + ...)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085 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;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001089
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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098
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})