Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(894)

Side by Side Diff: third_party/fdlibm/fdlibm.js

Issue 411263004: Implement trigonometric functions using a fdlibm port. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Added README.v8 Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // The following is adapted from fdlibm (http://www.netlib.org/fdlibm),
2 //
3 // ====================================================
4 // Copyright (C) 1993 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 for
17 // sin, cos, and tan, by Raymond Toy (rtoy@google.com).
18
19
20 var kTrig; // Initialized to a Float64Array during genesis and is not writable.
21
22 // Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For
23 // precision, r is returned as two values y0 and y1 such that r = y0 + y1
24 // to more than double precision.
25 macro REMPIO2(X)
26 var n, y0, y1;
27 var hx = %_DoubleHi(X);
28 var ix = hx & 0x7fffffff;
29
30 if (ix < 0x4002d97c) {
31 // |X| ~< 3*pi/4, special case with n = +/- 1
32 if (hx > 0) {
33 var z = X - kTrig[1];
34 if (ix != 0x3ff921fb) {
35 // 33+53 bit pi is good enough
36 y0 = z - kTrig[2];
37 y1 = (z - y0) - kTrig[2];
38 } else {
39 // near pi/2, use 33+33+53 bit pi
40 z -= kTrig[3];
41 y0 = z - kTrig[4];
42 y1 = (z - y0) - kTrig[4];
43 }
44 n = 1;
45 } else {
46 // Negative X
47 var z = X + kTrig[1];
48 if (ix != 0x3ff921fb) {
49 // 33+53 bit pi is good enough
50 y0 = z + kTrig[2];
51 y1 = (z - y0) + kTrig[2];
52 } else {
53 // near pi/2, use 33+33+53 bit pi
54 z += kTrig[3];
55 y0 = z + kTrig[4];
56 y1 = (z - y0) + kTrig[4];
57 }
58 n = -1;
59 }
60 } else if (ix <= 0x413921fb) {
61 // |X| ~<= 2^19*(pi/2), medium size
62 var t = MathAbs(X);
63 n = (t * kTrig[0] + 0.5) | 0;
64 var r = t - n * kTrig[1];
65 var w = n * kTrig[2];
66 // First round good to 85 bit
67 y0 = r - w;
68 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) {
69 // 2nd iteration needed, good to 118
70 t = r;
71 w = n * kTrig[3];
72 r = t - w;
73 w = n * kTrig[4] - ((t - r) - w);
74 y0 = r - w;
75 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) {
76 // 3rd iteration needed. 151 bits accuracy
77 t = r;
78 w = n * kTrig[5];
79 r = t - w;
80 w = n * kTrig[6] - ((t - r) - w);
81 y0 = r - w;
82 }
83 }
84 y1 = (r - y0) - w;
85 if (hx < 0) {
86 n = -n;
87 y0 = -y0;
88 y1 = -y1;
89 }
90 } else {
91 // Need to do full Payne-Hanek reduction here.
92 var r = %RemPiO2(X);
93 n = r[0];
94 y0 = r[1];
95 y1 = r[2];
96 }
97 endmacro
98
99
100 // __kernel_sin(X, Y, IY)
101 // kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
102 // Input X is assumed to be bounded by ~pi/4 in magnitude.
103 // Input Y is the tail of X so that x = X + Y.
104 //
105 // Algorithm
106 // 1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x.
107 // 2. ieee_sin(x) is approximated by a polynomial of degree 13 on
108 // [0,pi/4]
109 // 3 13
110 // sin(x) ~ x + S1*x + ... + S6*x
111 // where
112 //
113 // |ieee_sin(x) 2 4 6 8 10 12 | -58
114 // |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
115 // | x |
Raymond Toy 2014/07/30 19:55:05 Please fix the alignment. The exponents and right
Yang 2014/08/01 07:29:56 I aligned it to visually match the port you gave m
116 //
117 // 3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y
118 // ~ ieee_sin(X) + (1-X*X/2)*Y
119 // For better accuracy, let
120 // 3 2 2 2 2
121 // r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6))))
122 // then 3 2
123 // sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
124 //
125 macro RETURN_KERNELSIN(X, Y, SIGN)
126 var z = X * X;
127 var v = z * X;
128 var r = kTrig[8] + z * (kTrig[9] + z * (kTrig[10] +
129 z * (kTrig[11] + z * kTrig[12])));
130 return (X - ((z * (0.5 * Y - v * r) - Y) - v * kTrig[7])) SIGN;
131 endmacro
132
133 // __kernel_cos(X, Y)
134 // kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
135 // Input X is assumed to be bounded by ~pi/4 in magnitude.
136 // Input Y is the tail of X so that x = X + Y.
137 //
138 // Algorithm
139 // 1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x.
140 // 2. ieee_cos(x) is approximated by a polynomial of degree 14 on
141 // [0,pi/4]
142 // 4 14
143 // cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
144 // where the remez error is
145 //
146 // | 2 4 6 8 10 12 14 | -58
147 // |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
Raymond Toy 2014/07/30 19:55:05 Fix alignment of exponents.
Yang 2014/08/01 07:29:56 Done.
148 // | |
149 //
150 // 4 6 8 10 12 14
151 // 3. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
152 // ieee_cos(x) = 1 - x*x/2 + r
153 // since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y
154 // ~ ieee_cos(X) - X*Y,
155 // a correction term is necessary in ieee_cos(x) and hence
156 // cos(X+Y) = 1 - (X*X/2 - (r - X*Y))
157 // For better accuracy when x > 0.3, let qx = |x|/4 with
158 // the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
159 // Then
160 // cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)).
161 // Note that 1-qx and (X*X/2-qx) is EXACT here, and the
162 // magnitude of the latter is at least a quarter of X*X/2,
163 // thus, reducing the rounding error in the subtraction.
164 //
165 macro RETURN_KERNELCOS(X, Y, SIGN)
166 var ix = %_DoubleHi(X) & 0x7fffffff;
167 var z = X * X;
168 var r = z * (kTrig[13] + z * (kTrig[14] + z * (kTrig[15] +
169 z * (kTrig[16] + z * (kTrig[17] + z * kTrig[18])))));
170 if (ix < 0x3fd33333) {
171 return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
172 } else {
173 var qx;
174 if (ix > 0x3fe90000) {
175 qx = 0.28125;
176 } else {
177 qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0);
178 }
179 var hz = 0.5 * z - qx;
180 return (1 - qx - (hz - (z * r - X * Y))) SIGN;
181 }
182 endmacro
183
184 // kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
185 // Input x is assumed to be bounded by ~pi/4 in magnitude.
186 // Input y is the tail of x.
187 // Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1)
188 // is returned.
189 //
190 // Algorithm
191 // 1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x.
192 // 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
193 // 3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on
194 // [0,0.67434]
195 // 3 27
196 // tan(x) ~ x + T1*x + ... + T13*x
197 // where
198 //
199 // |ieee_tan(x) 2 4 26 | -59.2
200 // |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
Raymond Toy 2014/07/30 19:55:05 Line up exponents correctly.
Yang 2014/08/01 07:29:56 Done.
201 // | x |
202 //
203 // Note: ieee_tan(x+y) = ieee_tan(x) + tan'(x)*y
204 // ~ ieee_tan(x) + (1+x*x)*y
205 // Therefore, for better accuracy in computing ieee_tan(x+y), let
206 // 3 2 2 2 2
207 // r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
208 // then
209 // 3 2
210 // tan(x+y) = x + (T1*x + (x *(r+y)+y))
211 //
212 // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
213 // tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y))
214 // = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y)))
215 //
216 // Set returnTan to 1 for tan; -1 for cot. Anything else is illegal
217 // and will cause incorrect results.
218 //
219 function KernelTan(x, y, returnTan) {
220 var z;
221 var w;
222 var hx = %_DoubleHi(x);
223 var ix = hx & 0x7fffffff;
224
225 if (ix < 0x3e300000) {
226 // x < 2^-28
227 if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
228 return 1 / MathAbs(x);
229 } else {
230 if (returnTan == 1) {
231 return x;
232 } else {
233 // Compute -1/(x + y) carefully
234 var w = x + y;
235 var z = %_ConstructDouble(%_DoubleHi(w), 0);
236 var v = y - (z - x);
237 var a = -1 / w;
238 var t = %_ConstructDouble(%_DoubleHi(a), 0);
239 var s = 1 + t * z;
240 return t + a * (s + t * v);
241 }
242 }
243 }
244 if (ix >= 0x3fe59429) {
245 // |x| > .6744
246 if (x < 0) {
247 x = -x;
248 y = -y;
249 }
250 z = kTrig[32] - x;
251 w = kTrig[33] - y;
252 x = z + w;
253 y = 0;
254 }
255 z = x * x;
256 w = z * z;
257
258 var r = kTrig[20] + w * (kTrig[22] + w * (kTrig[24] +
259 w * (kTrig[26] + w * (kTrig[28] + w * kTrig[30]))));
260 var v = z * (kTrig[21] + w * (kTrig[23] + w * (kTrig[25] +
261 w * (kTrig[27] + w * (kTrig[29] + w * kTrig[31])))));
262 var s = z * x;
263 r = y + z * (s * (r + v) + y);
264 r = r + kTrig[19] * s;
265 w = x + r;
266 if (ix >= 0x3fe59428) {
267 return (1 - ((hx >> 30) & 2)) *
268 (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r)));
269 }
270 if (returnTan == 1) {
271 return w;
272 } else {
273 z = %_ConstructDouble(%_DoubleHi(w), 0);
274 v = r - (z - x);
275 var a = -1 / w;
276 var t = %_ConstructDouble(%_DoubleHi(a), 0);
277 s = 1 + t * z;
278 return t + a * (s + t * v);
279 }
280 }
281
282 function MathSinSlow(x) {
283 REMPIO2(x);
Raymond Toy 2014/07/30 19:55:05 Since we're doing the slow path anyway, I think it
Yang 2014/08/01 07:29:56 We just generally don't care about performance for
284 var sign = 1 - (n & 2);
285 if (n & 1) {
286 RETURN_KERNELCOS(y0, y1, * sign);
287 } else {
288 RETURN_KERNELSIN(y0, y1, * sign);
289 }
290 }
291
292 function MathCosSlow(x) {
293 REMPIO2(x);
294 if (n & 1) {
295 var sign = (n & 2) - 1;
296 RETURN_KERNELSIN(y0, y1, * sign);
297 } else {
298 var sign = 1 - (n & 2);
299 RETURN_KERNELCOS(y0, y1, * sign);
300 }
301 }
302
303 // ECMA 262 - 15.8.2.16
304 function MathSin(x) {
305 x = x * 1; // Convert to number.
306 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
307 // |x| < pi/4, approximately. No reduction needed.
308 RETURN_KERNELSIN(x, 0, /* empty */);
309 }
310 return MathSinSlow(x);
311 }
312
313 // ECMA 262 - 15.8.2.7
314 function MathCos(x) {
315 x = x * 1; // Convert to number.
316 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
317 // |x| < pi/4, approximately. No reduction needed.
318 RETURN_KERNELCOS(x, 0, /* empty */);
319 }
320 return MathCosSlow(x);
321 }
322
323 // ECMA 262 - 15.8.2.18
324 function MathTan(x) {
325 x = x * 1; // Convert to number.
326 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
327 // |x| < pi/4, approximately. No reduction needed.
328 return KernelTan(x, 0, 1);
329 }
330 REMPIO2(x);
Raymond Toy 2014/07/30 19:55:05 Like for MathSinSlow and MathCosSlow, I think you
Yang 2014/08/01 07:29:56 Done.
331 return KernelTan(y0, y1, (n & 1) ? -1 : 1);
332 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698