Fixed compilation error
[bochs-mirror.git] / fpu / fsincos.cc
blob4ba50f14dbcd40e11821da11d1d8b6c282259657
1 /*============================================================================
2 This source file is an extension to the SoftFloat IEC/IEEE Floating-point
3 Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
4 floating point emulation.
6 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
7 been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
8 RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
9 AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
10 COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
11 EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
12 INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
13 OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
15 Derivative works are acceptable, even for commercial purposes, so long as
16 (1) the source code for the derivative work includes prominent notice that
17 the work is derivative, and (2) the source code includes prominent notice with
18 these four paragraphs for those parts of this code that are retained.
19 =============================================================================*/
21 /*============================================================================
22 * Written for Bochs (x86 achitecture simulator) by
23 * Stanislav Shwartsman [sshwarts at sourceforge net]
24 * ==========================================================================*/
26 #define FLOAT128
28 #define USE_estimateDiv128To64
29 #include "softfloatx80.h"
30 #include "softfloat-round-pack.h"
31 #include "fpu_constant.h"
33 static const floatx80 floatx80_one = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
35 /* reduce trigonometric function argument using 128-bit precision
36 M_PI approximation */
37 static Bit64u argument_reduction_kernel(Bit64u aSig0, int Exp, Bit64u *zSig0, Bit64u *zSig1)
39 Bit64u term0, term1, term2;
40 Bit64u aSig1 = 0;
42 shortShift128Left(aSig1, aSig0, Exp, &aSig1, &aSig0);
43 Bit64u q = estimateDiv128To64(aSig1, aSig0, FLOAT_PI_HI);
44 mul128By64To192(FLOAT_PI_HI, FLOAT_PI_LO, q, &term0, &term1, &term2);
45 sub128(aSig1, aSig0, term0, term1, zSig1, zSig0);
46 while ((Bit64s)(*zSig1) < 0) {
47 --q;
48 add192(*zSig1, *zSig0, term2, 0, FLOAT_PI_HI, FLOAT_PI_LO, zSig1, zSig0, &term2);
50 *zSig1 = term2;
51 return q;
54 static int reduce_trig_arg(int expDiff, int &zSign, Bit64u &aSig0, Bit64u &aSig1)
56 Bit64u term0, term1, q = 0;
58 if (expDiff < 0) {
59 shift128Right(aSig0, 0, 1, &aSig0, &aSig1);
60 expDiff = 0;
62 if (expDiff > 0) {
63 q = argument_reduction_kernel(aSig0, expDiff, &aSig0, &aSig1);
65 else {
66 if (FLOAT_PI_HI <= aSig0) {
67 aSig0 -= FLOAT_PI_HI;
68 q = 1;
72 shift128Right(FLOAT_PI_HI, FLOAT_PI_LO, 1, &term0, &term1);
73 if (! lt128(aSig0, aSig1, term0, term1))
75 int lt = lt128(term0, term1, aSig0, aSig1);
76 int eq = eq128(aSig0, aSig1, term0, term1);
78 if ((eq && (q & 1)) || lt) {
79 zSign = !zSign;
80 ++q;
82 if (lt) sub128(FLOAT_PI_HI, FLOAT_PI_LO, aSig0, aSig1, &aSig0, &aSig1);
85 return (int)(q & 3);
88 #define SIN_ARR_SIZE 9
89 #define COS_ARR_SIZE 9
91 static float128 sin_arr[SIN_ARR_SIZE] =
93 PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
94 PACK_FLOAT_128(0xbffc555555555555, 0x5555555555555555), /* 3 */
95 PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /* 5 */
96 PACK_FLOAT_128(0xbff2a01a01a01a01, 0xa01a01a01a01a01a), /* 7 */
97 PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /* 9 */
98 PACK_FLOAT_128(0xbfe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */
99 PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */
100 PACK_FLOAT_128(0xbfd6ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 15 */
101 PACK_FLOAT_128(0x3fce952c77030ad4, 0xa6b2605197771b00) /* 17 */
104 static float128 cos_arr[COS_ARR_SIZE] =
106 PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 0 */
107 PACK_FLOAT_128(0xbffe000000000000, 0x0000000000000000), /* 2 */
108 PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /* 4 */
109 PACK_FLOAT_128(0xbff56c16c16c16c1, 0x6c16c16c16c16c17), /* 6 */
110 PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /* 8 */
111 PACK_FLOAT_128(0xbfe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */
112 PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */
113 PACK_FLOAT_128(0xbfda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */
114 PACK_FLOAT_128(0x3fd2ae7f3e733b81, 0xf11d8656b0ee8cb0) /* 16 */
117 extern float128 OddPoly (float128 x, float128 *arr, unsigned n, float_status_t &status);
119 /* 0 <= x <= pi/4 */
120 BX_CPP_INLINE float128 poly_sin(float128 x, float_status_t &status)
122 // 3 5 7 9 11 13 15
123 // x x x x x x x
124 // sin (x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- =
125 // 3! 5! 7! 9! 11! 13! 15!
127 // 2 4 6 8 10 12 14
128 // x x x x x x x
129 // = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- ] =
130 // 3! 5! 7! 9! 11! 13! 15!
132 // 3 3
133 // -- 4k -- 4k+2
134 // p(x) = > C * x > 0 q(x) = > C * x < 0
135 // -- 2k -- 2k+1
136 // k=0 k=0
138 // 2
139 // sin(x) ~ x * [ p(x) + x * q(x) ]
142 return OddPoly(x, sin_arr, SIN_ARR_SIZE, status);
145 extern float128 EvenPoly(float128 x, float128 *arr, unsigned n, float_status_t &status);
147 /* 0 <= x <= pi/4 */
148 BX_CPP_INLINE float128 poly_cos(float128 x, float_status_t &status)
150 // 2 4 6 8 10 12 14
151 // x x x x x x x
152 // cos (x) ~ 1 - --- + --- - --- + --- - ---- + ---- - ----
153 // 2! 4! 6! 8! 10! 12! 14!
155 // 3 3
156 // -- 4k -- 4k+2
157 // p(x) = > C * x > 0 q(x) = > C * x < 0
158 // -- 2k -- 2k+1
159 // k=0 k=0
161 // 2
162 // cos(x) ~ [ p(x) + x * q(x) ]
165 return EvenPoly(x, cos_arr, COS_ARR_SIZE, status);
168 BX_CPP_INLINE void sincos_invalid(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
170 if (sin_a) *sin_a = a;
171 if (cos_a) *cos_a = a;
174 BX_CPP_INLINE void sincos_tiny_argument(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
176 if (sin_a) *sin_a = a;
177 if (cos_a) *cos_a = floatx80_one;
180 static floatx80 sincos_approximation(int neg, float128 r, Bit64u quotient, float_status_t &status)
182 if (quotient & 0x1) {
183 r = poly_cos(r, status);
184 neg = 0;
185 } else {
186 r = poly_sin(r, status);
189 floatx80 result = float128_to_floatx80(r, status);
190 if (quotient & 0x2)
191 neg = ! neg;
193 if (neg)
194 floatx80_chs(result);
196 return result;
199 // =================================================
200 // FSINCOS Compute sin(x) and cos(x)
201 // =================================================
204 // Uses the following identities:
205 // ----------------------------------------------------------
207 // sin(-x) = -sin(x)
208 // cos(-x) = cos(x)
210 // sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
211 // cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
213 // sin(x+ pi/2) = cos(x)
214 // sin(x+ pi) = -sin(x)
215 // sin(x+3pi/2) = -cos(x)
216 // sin(x+2pi) = sin(x)
219 int fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a, float_status_t &status)
221 Bit64u aSig0, aSig1 = 0;
222 Bit32s aExp, zExp, expDiff;
223 int aSign, zSign;
224 int q = 0;
226 // handle unsupported extended double-precision floating encodings
227 if (floatx80_is_unsupported(a))
229 goto invalid;
232 aSig0 = extractFloatx80Frac(a);
233 aExp = extractFloatx80Exp(a);
234 aSign = extractFloatx80Sign(a);
236 /* invalid argument */
237 if (aExp == 0x7FFF) {
238 if ((Bit64u) (aSig0<<1)) {
239 sincos_invalid(sin_a, cos_a, propagateFloatx80NaN(a, status));
240 return 0;
243 invalid:
244 float_raise(status, float_flag_invalid);
245 sincos_invalid(sin_a, cos_a, floatx80_default_nan);
246 return 0;
249 if (aExp == 0) {
250 if (aSig0 == 0) {
251 sincos_tiny_argument(sin_a, cos_a, a);
252 return 0;
255 float_raise(status, float_flag_denormal);
257 /* handle pseudo denormals */
258 if (! (aSig0 & BX_CONST64(0x8000000000000000)))
260 float_raise(status, float_flag_inexact);
261 if (sin_a)
262 float_raise(status, float_flag_underflow);
263 sincos_tiny_argument(sin_a, cos_a, a);
264 return 0;
267 normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
270 zSign = aSign;
271 zExp = EXP_BIAS;
272 expDiff = aExp - zExp;
274 /* argument is out-of-range */
275 if (expDiff >= 63)
276 return -1;
278 float_raise(status, float_flag_inexact);
280 if (expDiff < -1) { // doesn't require reduction
281 if (expDiff <= -68) {
282 a = packFloatx80(aSign, aExp, aSig0);
283 sincos_tiny_argument(sin_a, cos_a, a);
284 return 0;
286 zExp = aExp;
288 else {
289 q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1);
292 /* **************************** */
293 /* argument reduction completed */
294 /* **************************** */
296 /* using float128 for approximation */
297 float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1, status);
299 if (aSign) q = -q;
300 if (sin_a) *sin_a = sincos_approximation(zSign, r, q, status);
301 if (cos_a) *cos_a = sincos_approximation(zSign, r, q+1, status);
303 return 0;
306 int fsin(floatx80 &a, float_status_t &status)
308 return fsincos(a, &a, 0, status);
311 int fcos(floatx80 &a, float_status_t &status)
313 return fsincos(a, 0, &a, status);
316 // =================================================
317 // FPTAN Compute tan(x)
318 // =================================================
321 // Uses the following identities:
323 // 1. ----------------------------------------------------------
325 // sin(-x) = -sin(x)
326 // cos(-x) = cos(x)
328 // sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
329 // cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
331 // sin(x+ pi/2) = cos(x)
332 // sin(x+ pi) = -sin(x)
333 // sin(x+3pi/2) = -cos(x)
334 // sin(x+2pi) = sin(x)
336 // 2. ----------------------------------------------------------
338 // sin(x)
339 // tan(x) = ------
340 // cos(x)
343 int ftan(floatx80 &a, float_status_t &status)
345 Bit64u aSig0, aSig1 = 0;
346 Bit32s aExp, zExp, expDiff;
347 int aSign, zSign;
348 int q = 0;
350 // handle unsupported extended double-precision floating encodings
351 if (floatx80_is_unsupported(a))
353 goto invalid;
356 aSig0 = extractFloatx80Frac(a);
357 aExp = extractFloatx80Exp(a);
358 aSign = extractFloatx80Sign(a);
360 /* invalid argument */
361 if (aExp == 0x7FFF) {
362 if ((Bit64u) (aSig0<<1))
364 a = propagateFloatx80NaN(a, status);
365 return 0;
368 invalid:
369 float_raise(status, float_flag_invalid);
370 a = floatx80_default_nan;
371 return 0;
374 if (aExp == 0) {
375 if (aSig0 == 0) return 0;
376 float_raise(status, float_flag_denormal);
377 /* handle pseudo denormals */
378 if (! (aSig0 & BX_CONST64(0x8000000000000000)))
380 float_raise(status, float_flag_inexact | float_flag_underflow);
381 return 0;
383 normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
386 zSign = aSign;
387 zExp = EXP_BIAS;
388 expDiff = aExp - zExp;
390 /* argument is out-of-range */
391 if (expDiff >= 63)
392 return -1;
394 float_raise(status, float_flag_inexact);
396 if (expDiff < -1) { // doesn't require reduction
397 if (expDiff <= -68) {
398 a = packFloatx80(aSign, aExp, aSig0);
399 return 0;
401 zExp = aExp;
403 else {
404 q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1);
407 /* **************************** */
408 /* argument reduction completed */
409 /* **************************** */
411 /* using float128 for approximation */
412 float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1, status);
414 float128 sin_r = poly_sin(r, status);
415 float128 cos_r = poly_cos(r, status);
417 if (q & 0x1) {
418 r = float128_div(cos_r, sin_r, status);
419 zSign = ! zSign;
420 } else {
421 r = float128_div(sin_r, cos_r, status);
424 a = float128_to_floatx80(r, status);
425 if (zSign)
426 floatx80_chs(a);
428 return 0;