OLD | NEW |
1 // The following is adapted from fdlibm (http://www.netlib.org/fdlibm), | 1 // The following is adapted from fdlibm (http://www.netlib.org/fdlibm), |
2 // | 2 // |
3 // ==================================================== | 3 // ==================================================== |
4 // Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved. | 4 // Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved. |
5 // | 5 // |
6 // Developed at SunSoft, a Sun Microsystems, Inc. business. | 6 // Developed at SunSoft, a Sun Microsystems, Inc. business. |
7 // Permission to use, copy, modify, and distribute this | 7 // Permission to use, copy, modify, and distribute this |
8 // software is freely granted, provided that this notice | 8 // software is freely granted, provided that this notice |
9 // is preserved. | 9 // is preserved. |
10 // ==================================================== | 10 // ==================================================== |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 } | 127 } |
128 } else { | 128 } else { |
129 // Need to do full Payne-Hanek reduction here. | 129 // Need to do full Payne-Hanek reduction here. |
130 n = %RemPiO2(X, rempio2result); | 130 n = %RemPiO2(X, rempio2result); |
131 y0 = rempio2result[0]; | 131 y0 = rempio2result[0]; |
132 y1 = rempio2result[1]; | 132 y1 = rempio2result[1]; |
133 } | 133 } |
134 endmacro | 134 endmacro |
135 | 135 |
136 | 136 |
137 // __kernel_sin(X, Y, IY) | |
138 // kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854 | |
139 // Input X is assumed to be bounded by ~pi/4 in magnitude. | |
140 // Input Y is the tail of X so that x = X + Y. | |
141 // | |
142 // Algorithm | |
143 // 1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x. | |
144 // 2. ieee_sin(x) is approximated by a polynomial of degree 13 on | |
145 // [0,pi/4] | |
146 // 3 13 | |
147 // sin(x) ~ x + S1*x + ... + S6*x | |
148 // where | |
149 // | |
150 // |ieee_sin(x) 2 4 6 8 10 12 | -58 | |
151 // |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 | |
152 // | x | | |
153 // | |
154 // 3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y | |
155 // ~ ieee_sin(X) + (1-X*X/2)*Y | |
156 // For better accuracy, let | |
157 // 3 2 2 2 2 | |
158 // r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6)))) | |
159 // then 3 2 | |
160 // sin(x) = X + (S1*X + (X *(r-Y/2)+Y)) | |
161 // | |
162 define S1 = -1.66666666666666324348e-01; | |
163 define S2 = 8.33333333332248946124e-03; | |
164 define S3 = -1.98412698298579493134e-04; | |
165 define S4 = 2.75573137070700676789e-06; | |
166 define S5 = -2.50507602534068634195e-08; | |
167 define S6 = 1.58969099521155010221e-10; | |
168 | |
169 macro RETURN_KERNELSIN(X, Y, SIGN) | |
170 var z = X * X; | |
171 var v = z * X; | |
172 var r = S2 + z * (S3 + z * (S4 + z * (S5 + z * S6))); | |
173 return (X - ((z * (0.5 * Y - v * r) - Y) - v * S1)) SIGN; | |
174 endmacro | |
175 | |
176 // __kernel_cos(X, Y) | |
177 // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 | |
178 // Input X is assumed to be bounded by ~pi/4 in magnitude. | |
179 // Input Y is the tail of X so that x = X + Y. | |
180 // | |
181 // Algorithm | |
182 // 1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x. | |
183 // 2. ieee_cos(x) is approximated by a polynomial of degree 14 on | |
184 // [0,pi/4] | |
185 // 4 14 | |
186 // cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x | |
187 // where the remez error is | |
188 // | |
189 // | 2 4 6 8 10 12 14 | -58 | |
190 // |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 | |
191 // | | | |
192 // | |
193 // 4 6 8 10 12 14 | |
194 // 3. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then | |
195 // ieee_cos(x) = 1 - x*x/2 + r | |
196 // since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y | |
197 // ~ ieee_cos(X) - X*Y, | |
198 // a correction term is necessary in ieee_cos(x) and hence | |
199 // cos(X+Y) = 1 - (X*X/2 - (r - X*Y)) | |
200 // For better accuracy when x > 0.3, let qx = |x|/4 with | |
201 // the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. | |
202 // Then | |
203 // cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)). | |
204 // Note that 1-qx and (X*X/2-qx) is EXACT here, and the | |
205 // magnitude of the latter is at least a quarter of X*X/2, | |
206 // thus, reducing the rounding error in the subtraction. | |
207 // | |
208 define C1 = 4.16666666666666019037e-02; | |
209 define C2 = -1.38888888888741095749e-03; | |
210 define C3 = 2.48015872894767294178e-05; | |
211 define C4 = -2.75573143513906633035e-07; | |
212 define C5 = 2.08757232129817482790e-09; | |
213 define C6 = -1.13596475577881948265e-11; | |
214 | |
215 macro RETURN_KERNELCOS(X, Y, SIGN) | |
216 var ix = %_DoubleHi(X) & 0x7fffffff; | |
217 var z = X * X; | |
218 var r = z * (C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6))))); | |
219 if (ix < 0x3fd33333) { // |x| ~< 0.3 | |
220 return (1 - (0.5 * z - (z * r - X * Y))) SIGN; | |
221 } else { | |
222 var qx; | |
223 if (ix > 0x3fe90000) { // |x| > 0.78125 | |
224 qx = 0.28125; | |
225 } else { | |
226 qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0); | |
227 } | |
228 var hz = 0.5 * z - qx; | |
229 return (1 - qx - (hz - (z * r - X * Y))) SIGN; | |
230 } | |
231 endmacro | |
232 | |
233 | |
234 // kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 | 137 // 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. | 138 // Input x is assumed to be bounded by ~pi/4 in magnitude. |
236 // Input y is the tail of x. | 139 // Input y is the tail of x. |
237 // Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1) | 140 // Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1) |
238 // is returned. | 141 // is returned. |
239 // | 142 // |
240 // Algorithm | 143 // Algorithm |
241 // 1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x. | 144 // 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. | 145 // 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 | 146 // 3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 } else { | 241 } else { |
339 z = %_ConstructDouble(%_DoubleHi(w), 0); | 242 z = %_ConstructDouble(%_DoubleHi(w), 0); |
340 v = r - (z - x); | 243 v = r - (z - x); |
341 var a = -1 / w; | 244 var a = -1 / w; |
342 var t = %_ConstructDouble(%_DoubleHi(a), 0); | 245 var t = %_ConstructDouble(%_DoubleHi(a), 0); |
343 s = 1 + t * z; | 246 s = 1 + t * z; |
344 return t + a * (s + t * v); | 247 return t + a * (s + t * v); |
345 } | 248 } |
346 } | 249 } |
347 | 250 |
348 function MathSinSlow(x) { | |
349 REMPIO2(x); | |
350 var sign = 1 - (n & 2); | |
351 if (n & 1) { | |
352 RETURN_KERNELCOS(y0, y1, * sign); | |
353 } else { | |
354 RETURN_KERNELSIN(y0, y1, * sign); | |
355 } | |
356 } | |
357 | |
358 function MathCosSlow(x) { | |
359 REMPIO2(x); | |
360 if (n & 1) { | |
361 var sign = (n & 2) - 1; | |
362 RETURN_KERNELSIN(y0, y1, * sign); | |
363 } else { | |
364 var sign = 1 - (n & 2); | |
365 RETURN_KERNELCOS(y0, y1, * sign); | |
366 } | |
367 } | |
368 | |
369 // ECMA 262 - 15.8.2.16 | |
370 function MathSin(x) { | |
371 x = +x; // Convert to number. | |
372 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | |
373 // |x| < pi/4, approximately. No reduction needed. | |
374 RETURN_KERNELSIN(x, 0, /* empty */); | |
375 } | |
376 return +MathSinSlow(x); | |
377 } | |
378 | |
379 // ECMA 262 - 15.8.2.7 | |
380 function MathCos(x) { | |
381 x = +x; // Convert to number. | |
382 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | |
383 // |x| < pi/4, approximately. No reduction needed. | |
384 RETURN_KERNELCOS(x, 0, /* empty */); | |
385 } | |
386 return +MathCosSlow(x); | |
387 } | |
388 | |
389 // ECMA 262 - 15.8.2.18 | 251 // ECMA 262 - 15.8.2.18 |
390 function MathTan(x) { | 252 function MathTan(x) { |
391 x = x * 1; // Convert to number. | 253 x = x * 1; // Convert to number. |
392 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | 254 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { |
393 // |x| < pi/4, approximately. No reduction needed. | 255 // |x| < pi/4, approximately. No reduction needed. |
394 return KernelTan(x, 0, 1); | 256 return KernelTan(x, 0, 1); |
395 } | 257 } |
396 REMPIO2(x); | 258 REMPIO2(x); |
397 return KernelTan(y0, y1, (n & 1) ? -1 : 1); | 259 return KernelTan(y0, y1, (n & 1) ? -1 : 1); |
398 } | 260 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 } else { | 419 } else { |
558 // |x| > 22, return +/- 1 | 420 // |x| > 22, return +/- 1 |
559 z = 1; | 421 z = 1; |
560 } | 422 } |
561 return (x >= 0) ? z : -z; | 423 return (x >= 0) ? z : -z; |
562 } | 424 } |
563 | 425 |
564 //------------------------------------------------------------------- | 426 //------------------------------------------------------------------- |
565 | 427 |
566 utils.InstallFunctions(GlobalMath, DONT_ENUM, [ | 428 utils.InstallFunctions(GlobalMath, DONT_ENUM, [ |
567 "cos", MathCos, | |
568 "sin", MathSin, | |
569 "tan", MathTan, | 429 "tan", MathTan, |
570 "sinh", MathSinh, | 430 "sinh", MathSinh, |
571 "cosh", MathCosh, | 431 "cosh", MathCosh, |
572 "tanh", MathTanh | 432 "tanh", MathTanh |
573 ]); | 433 ]); |
574 | 434 |
575 %SetForceInlineFlag(MathSin); | |
576 %SetForceInlineFlag(MathCos); | |
577 | |
578 }) | 435 }) |
OLD | NEW |