1 | /* $Id: testmath.c 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * Testcase for the no-crt math stuff.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2019 Oracle Corporation
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License (GPL) as published by the Free Software
|
---|
13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | */
|
---|
17 |
|
---|
18 |
|
---|
19 | /*********************************************************************************************************************************
|
---|
20 | * Header Files *
|
---|
21 | *********************************************************************************************************************************/
|
---|
22 | #ifndef MATHTEST_STANDALONE
|
---|
23 | # include <iprt/assert.h>
|
---|
24 | # include <math.h>
|
---|
25 | # undef printf
|
---|
26 | # define printf RTAssertMsg2Weak
|
---|
27 | #else
|
---|
28 | # include <stdio.h>
|
---|
29 | # include <math.h>
|
---|
30 | #endif
|
---|
31 |
|
---|
32 | /* gcc starting with version 4.3 uses the MPFR library which results in more accurate results. gcc-4.3.1 seems to emit the less accurate result. So just allow both results. */
|
---|
33 | #define SIN180a -0.8011526357338304777463731115L
|
---|
34 | #define SIN180b -0.801152635733830477871L
|
---|
35 |
|
---|
36 | static void bitch(const char *pszWhat, const long double *plrdResult, const long double *plrdExpected)
|
---|
37 | {
|
---|
38 | const unsigned char *pach1 = (const unsigned char *)plrdResult;
|
---|
39 | const unsigned char *pach2 = (const unsigned char *)plrdExpected;
|
---|
40 | #ifndef MATHTEST_STANDALONE
|
---|
41 | printf("error: %s - %d instead of %d\n", pszWhat, (int)(*plrdResult * 100000), (int)(*plrdExpected * 100000));
|
---|
42 | #else
|
---|
43 | printf("error: %s - %.25f instead of %.25f\n", pszWhat, (double)*plrdResult, (double)*plrdExpected);
|
---|
44 | #endif
|
---|
45 | printf(" %02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x\n", pach1[0], pach1[1], pach1[2], pach1[3], pach1[4], pach1[5], pach1[6], pach1[7], pach1[8], pach1[9]);
|
---|
46 | printf(" %02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x\n", pach2[0], pach2[1], pach2[2], pach2[3], pach2[4], pach2[5], pach2[6], pach2[7], pach2[8], pach2[9]);
|
---|
47 | }
|
---|
48 |
|
---|
49 | static void bitchll(const char *pszWhat, long long llResult, long long llExpected)
|
---|
50 | {
|
---|
51 | #if defined(__MINGW32__) && !defined(Assert)
|
---|
52 | printf("error: %s - %I64d instead of %I64d\n", pszWhat, llResult, llExpected);
|
---|
53 | #else
|
---|
54 | printf("error: %s - %lld instead of %lld\n", pszWhat, llResult, llExpected);
|
---|
55 | #endif
|
---|
56 | }
|
---|
57 |
|
---|
58 | static void bitchl(const char *pszWhat, long lResult, long lExpected)
|
---|
59 | {
|
---|
60 | printf("error: %s - %ld instead of %ld\n", pszWhat, lResult, lExpected);
|
---|
61 | }
|
---|
62 |
|
---|
63 | extern int testsin(void)
|
---|
64 | {
|
---|
65 | return sinl(180.0L) == SIN180a || sinl(180.0L) == SIN180b;
|
---|
66 | }
|
---|
67 |
|
---|
68 | extern int testremainder(void)
|
---|
69 | {
|
---|
70 | static double s_rd1 = 2.5;
|
---|
71 | static double s_rd2 = 2.0;
|
---|
72 | static double s_rd3 = 0.5;
|
---|
73 | return remainder(s_rd1, s_rd2) == s_rd3;
|
---|
74 | }
|
---|
75 |
|
---|
76 | static __inline__ void set_cw(unsigned cw)
|
---|
77 | {
|
---|
78 | __asm __volatile("fldcw %0" : : "m" (cw));
|
---|
79 | }
|
---|
80 |
|
---|
81 | static __inline__ unsigned get_cw(void)
|
---|
82 | {
|
---|
83 | unsigned cw;
|
---|
84 | __asm __volatile("fstcw %0" : "=m" (cw));
|
---|
85 | return cw & 0xffff;
|
---|
86 | }
|
---|
87 |
|
---|
88 | static long double check_lrd(const long double lrd, const unsigned long long ull, const unsigned short us)
|
---|
89 | {
|
---|
90 | static volatile long double lrd2;
|
---|
91 | lrd2 = lrd;
|
---|
92 | if ( *(unsigned long long *)&lrd2 != ull
|
---|
93 | || ((unsigned short *)&lrd2)[4] != us)
|
---|
94 | {
|
---|
95 | #if defined(__MINGW32__) && !defined(Assert)
|
---|
96 | printf("%I64x:%04x instead of %I64x:%04x\n", *(unsigned long long *)&lrd2, ((unsigned short *)&lrd2)[4], ull, us);
|
---|
97 | #else
|
---|
98 | printf("%llx:%04x instead of %llx:%04x\n", *(unsigned long long *)&lrd2, ((unsigned short *)&lrd2)[4], ull, us);
|
---|
99 | #endif
|
---|
100 | __asm__("int $3\n");
|
---|
101 | }
|
---|
102 | return lrd;
|
---|
103 | }
|
---|
104 |
|
---|
105 |
|
---|
106 | static long double make_lrd(const unsigned long long ull, const unsigned short us)
|
---|
107 | {
|
---|
108 | union
|
---|
109 | {
|
---|
110 | long double lrd;
|
---|
111 | struct
|
---|
112 | {
|
---|
113 | unsigned long long ull;
|
---|
114 | unsigned short us;
|
---|
115 | } i;
|
---|
116 | } u;
|
---|
117 |
|
---|
118 | u.i.ull = ull;
|
---|
119 | u.i.us = us;
|
---|
120 | return u.lrd;
|
---|
121 | }
|
---|
122 |
|
---|
123 | static long double check_lrd_cw(const long double lrd, const unsigned long long ull, const unsigned short us, const unsigned cw)
|
---|
124 | {
|
---|
125 | set_cw(cw);
|
---|
126 | if (cw != get_cw())
|
---|
127 | {
|
---|
128 | printf("get_cw() -> %#x expected %#x\n", get_cw(), cw);
|
---|
129 | __asm__("int $3\n");
|
---|
130 | }
|
---|
131 | return check_lrd(lrd, ull, us);
|
---|
132 | }
|
---|
133 |
|
---|
134 | static long double make_lrd_cw(unsigned long long ull, unsigned short us, unsigned cw)
|
---|
135 | {
|
---|
136 | set_cw(cw);
|
---|
137 | return check_lrd_cw(make_lrd(ull, us), ull, us, cw);
|
---|
138 | }
|
---|
139 |
|
---|
140 | extern int testmath(void)
|
---|
141 | {
|
---|
142 | unsigned cErrors = 0;
|
---|
143 | long double lrdResult;
|
---|
144 | long double lrdExpect;
|
---|
145 | long double lrd;
|
---|
146 | #define CHECK(operation, expect) \
|
---|
147 | do { \
|
---|
148 | lrdExpect = expect; \
|
---|
149 | lrdResult = operation; \
|
---|
150 | if (lrdResult != lrdExpect) \
|
---|
151 | { \
|
---|
152 | bitch(#operation, &lrdResult, &lrdExpect); \
|
---|
153 | cErrors++; \
|
---|
154 | } \
|
---|
155 | } while (0)
|
---|
156 |
|
---|
157 | long long llResult;
|
---|
158 | long long llExpect;
|
---|
159 | #define CHECKLL(operation, expect) \
|
---|
160 | do { \
|
---|
161 | llExpect = expect; \
|
---|
162 | llResult = operation; \
|
---|
163 | if (llResult != llExpect) \
|
---|
164 | { \
|
---|
165 | bitchll(#operation, llResult, llExpect); \
|
---|
166 | cErrors++; \
|
---|
167 | } \
|
---|
168 | } while (0)
|
---|
169 |
|
---|
170 | long lResult;
|
---|
171 | long lExpect;
|
---|
172 | #define CHECKL(operation, expect) \
|
---|
173 | do { \
|
---|
174 | lExpect = expect; \
|
---|
175 | lResult = operation; \
|
---|
176 | if (lResult != lExpect) \
|
---|
177 | { \
|
---|
178 | bitchl(#operation, lResult, lExpect); \
|
---|
179 | cErrors++; \
|
---|
180 | } \
|
---|
181 | } while (0)
|
---|
182 |
|
---|
183 | CHECK(atan2l(1.0L, 1.0L), 0.785398163397448309603L);
|
---|
184 | CHECK(atan2l(2.3L, 3.3L), 0.608689307327411694890L);
|
---|
185 |
|
---|
186 | CHECK(ceill(1.9L), 2.0L);
|
---|
187 | CHECK(ceill(4.5L), 5.0L);
|
---|
188 | CHECK(ceill(3.3L), 4.0L);
|
---|
189 | CHECK(ceill(6.1L), 7.0L);
|
---|
190 |
|
---|
191 | CHECK(floorl(1.9L), 1.0L);
|
---|
192 | CHECK(floorl(4.5L), 4.0L);
|
---|
193 | CHECK(floorl(7.3L), 7.0L);
|
---|
194 | CHECK(floorl(1234.1L), 1234.0L);
|
---|
195 | CHECK(floor(1233.1), 1233.0);
|
---|
196 | CHECK(floor(1239.98989898), 1239.0);
|
---|
197 | CHECK(floorf(9999.999), 9999.0);
|
---|
198 |
|
---|
199 | CHECK(ldexpl(1.0L, 1), 2.0L);
|
---|
200 | CHECK(ldexpl(1.0L, 10), 1024.0L);
|
---|
201 | CHECK(ldexpl(2.25L, 10), 2304.0L);
|
---|
202 |
|
---|
203 | CHECKLL(llrintl(1.0L), 1);
|
---|
204 | CHECKLL(llrintl(1.3L), 1);
|
---|
205 | CHECKLL(llrintl(1.5L), 2);
|
---|
206 | CHECKLL(llrintl(1.9L), 2);
|
---|
207 | CHECKLL(llrintf(123.34), 123);
|
---|
208 | CHECKLL(llrintf(-123.50), -124);
|
---|
209 | CHECKLL(llrint(42.42), 42);
|
---|
210 | CHECKLL(llrint(-2147483648.12343), -2147483648LL);
|
---|
211 | #if !defined(RT_ARCH_AMD64)
|
---|
212 | CHECKLL(lrint(-21474836499.12343), -2147483648LL);
|
---|
213 | CHECKLL(lrint(-2147483649932412.12343), -2147483648LL);
|
---|
214 | #else
|
---|
215 | CHECKLL(lrint(-21474836499.12343), -21474836499L);
|
---|
216 | CHECKLL(lrint(-2147483649932412.12343), -2147483649932412L);
|
---|
217 | #endif
|
---|
218 |
|
---|
219 | // __asm__("int $3");
|
---|
220 | CHECKL(lrintl(make_lrd_cw(000000000000000000ULL,000000,0x027f)), 0L);
|
---|
221 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x027f)), 0L);
|
---|
222 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x027f)), 0L);
|
---|
223 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x067f)), 0L);
|
---|
224 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x067f)), 0L);
|
---|
225 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0a7f)), 1L);
|
---|
226 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0a7f)), 1L);
|
---|
227 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0e7f)), 0L);
|
---|
228 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0e7f)), 0L);
|
---|
229 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x027f)), 0L);
|
---|
230 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x027f)), 0L);
|
---|
231 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x067f)), -1L);
|
---|
232 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x067f)), -1L);
|
---|
233 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0a7f)), 0L);
|
---|
234 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0a7f)), 0L);
|
---|
235 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0e7f)), 0L);
|
---|
236 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0e7f)), 0L);
|
---|
237 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x027f)), 0L);
|
---|
238 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x027f)), 0L);
|
---|
239 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x067f)), 0L);
|
---|
240 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x067f)), 0L);
|
---|
241 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0a7f)), 1L);
|
---|
242 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0a7f)), 1L);
|
---|
243 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0e7f)), 0L);
|
---|
244 | CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0e7f)), 0L);
|
---|
245 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x027f)), 0L);
|
---|
246 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x027f)), 0L);
|
---|
247 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x067f)), -1L);
|
---|
248 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x067f)), -1L);
|
---|
249 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0a7f)), 0L);
|
---|
250 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0a7f)), 0L);
|
---|
251 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0e7f)), 0L);
|
---|
252 | CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0e7f)), 0L);
|
---|
253 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x027f)), 32768L);
|
---|
254 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x027f)), 32768L);
|
---|
255 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x067f)), 32768L);
|
---|
256 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x067f)), 32768L);
|
---|
257 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0a7f)), 32768L);
|
---|
258 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0a7f)), 32768L);
|
---|
259 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0e7f)), 32768L);
|
---|
260 | CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0e7f)), 32768L);
|
---|
261 | #if !defined(RT_ARCH_AMD64)
|
---|
262 | /* c90 says that the constant is 2147483648 (which is not representable as a signed 32-bit
|
---|
263 | * value). To that constant you've then applied the negation operation. c90 doesn't have
|
---|
264 | * negative constants, only positive ones that have been negated. */
|
---|
265 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x027f)), (long)(-2147483647L - 1));
|
---|
266 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x027f)), (long)(-2147483647L - 1));
|
---|
267 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x067f)), (long)(-2147483647L - 1));
|
---|
268 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x067f)), (long)(-2147483647L - 1));
|
---|
269 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0a7f)), (long)(-2147483647L - 1));
|
---|
270 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0a7f)), (long)(-2147483647L - 1));
|
---|
271 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0e7f)), (long)(-2147483647L - 1));
|
---|
272 | CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0e7f)), (long)(-2147483647L - 1));
|
---|
273 | #endif
|
---|
274 | set_cw(0x27f);
|
---|
275 |
|
---|
276 | CHECK(logl(2.7182818284590452353602874713526625L), 1.0);
|
---|
277 |
|
---|
278 | CHECK(remainderl(1.0L, 1.0L), 0.0);
|
---|
279 | CHECK(remainderl(1.0L, 1.5L), -0.5);
|
---|
280 | CHECK(remainderl(42.0L, 34.25L), 7.75);
|
---|
281 | CHECK(remainderf(43.0, 34.25), 8.75);
|
---|
282 | CHECK(remainder(44.25, 34.25), 10.00);
|
---|
283 | double rd1 = 44.25;
|
---|
284 | double rd2 = 34.25;
|
---|
285 | CHECK(remainder(rd1, rd2), 10.00);
|
---|
286 | CHECK(remainder(2.5, 2.0), 0.5);
|
---|
287 | CHECK(remainder(2.5, 2.0), 0.5);
|
---|
288 | CHECK(remainder(2.5, 2.0), 0.5);
|
---|
289 | CHECKLL(testremainder(), 1);
|
---|
290 |
|
---|
291 |
|
---|
292 | /* Only works in extended precision, while double precision is default on BSD (including Darwin) */
|
---|
293 | set_cw(0x37f);
|
---|
294 | CHECK(rintl(1.0L), 1.0);
|
---|
295 | CHECK(rintl(1.4L), 1.0);
|
---|
296 | CHECK(rintl(1.3L), 1.0);
|
---|
297 | CHECK(rintl(0.9L), 1.0);
|
---|
298 | CHECK(rintl(3123.1232L), 3123.0);
|
---|
299 | CHECK(rint(3985.13454), 3985.0);
|
---|
300 | CHECK(rintf(9999.999), 10000.0);
|
---|
301 | set_cw(0x27f);
|
---|
302 |
|
---|
303 | CHECK(sinl(1.0L), 0.84147098480789650664L);
|
---|
304 | #if 0
|
---|
305 | lrd = 180.0L;
|
---|
306 | CHECK(sinl(lrd), -0.801152635733830477871L);
|
---|
307 | #else
|
---|
308 | lrd = 180.0L;
|
---|
309 | lrdExpect = SIN180a;
|
---|
310 | lrdResult = sinl(lrd);
|
---|
311 | if (lrdResult != lrdExpect)
|
---|
312 | {
|
---|
313 | lrdExpect = SIN180b;
|
---|
314 | if (lrdResult != lrdExpect)
|
---|
315 | {
|
---|
316 | bitch("sinl(lrd)", &lrdResult, &lrdExpect);
|
---|
317 | cErrors++;
|
---|
318 | }
|
---|
319 | }
|
---|
320 | #endif
|
---|
321 | #if 0
|
---|
322 | CHECK(sinl(180.0L), SIN180);
|
---|
323 | #else
|
---|
324 | lrdExpect = SIN180a;
|
---|
325 | lrdResult = sinl(180.0L);
|
---|
326 | if (lrdResult != lrdExpect)
|
---|
327 | {
|
---|
328 | lrdExpect = SIN180b;
|
---|
329 | if (lrdResult != lrdExpect)
|
---|
330 | {
|
---|
331 | bitch("sinl(180.0L)", &lrdResult, &lrdExpect);
|
---|
332 | cErrors++;
|
---|
333 | }
|
---|
334 | }
|
---|
335 | #endif
|
---|
336 | CHECKLL(testsin(), 1);
|
---|
337 |
|
---|
338 | CHECK(sqrtl(1.0L), 1.0);
|
---|
339 | CHECK(sqrtl(4.0L), 2.0);
|
---|
340 | CHECK(sqrtl(1525225.0L), 1235.0);
|
---|
341 |
|
---|
342 | CHECK(tanl(0.0L), 0.0);
|
---|
343 | CHECK(tanl(0.7853981633974483096156608458198757L), 1.0);
|
---|
344 |
|
---|
345 | CHECK(powl(0.0, 0.0), 1.0);
|
---|
346 | CHECK(powl(2.0, 2.0), 4.0);
|
---|
347 | CHECK(powl(3.0, 3.0), 27.0);
|
---|
348 |
|
---|
349 | return cErrors;
|
---|
350 | }
|
---|
351 |
|
---|
352 |
|
---|
353 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
354 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
355 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
356 | #if 0
|
---|
357 |
|
---|
358 | #define floatx_to_int32 floatx80_to_int32
|
---|
359 | #define floatx_to_int64 floatx80_to_int64
|
---|
360 | #define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero
|
---|
361 | #define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero
|
---|
362 | #define floatx_abs floatx80_abs
|
---|
363 | #define floatx_chs floatx80_chs
|
---|
364 | #define floatx_round_to_int(foo, bar) floatx80_round_to_int(foo, NULL)
|
---|
365 | #define floatx_compare floatx80_compare
|
---|
366 | #define floatx_compare_quiet floatx80_compare_quiet
|
---|
367 | #undef sin
|
---|
368 | #undef cos
|
---|
369 | #undef sqrt
|
---|
370 | #undef pow
|
---|
371 | #undef log
|
---|
372 | #undef tan
|
---|
373 | #undef atan2
|
---|
374 | #undef floor
|
---|
375 | #undef ceil
|
---|
376 | #undef ldexp
|
---|
377 | #define sin sinl
|
---|
378 | #define cos cosl
|
---|
379 | #define sqrt sqrtl
|
---|
380 | #define pow powl
|
---|
381 | #define log logl
|
---|
382 | #define tan tanl
|
---|
383 | #define atan2 atan2l
|
---|
384 | #define floor floorl
|
---|
385 | #define ceil ceill
|
---|
386 | #define ldexp ldexpl
|
---|
387 |
|
---|
388 |
|
---|
389 | typedef long double CPU86_LDouble;
|
---|
390 |
|
---|
391 | typedef union {
|
---|
392 | long double d;
|
---|
393 | struct {
|
---|
394 | unsigned long long lower;
|
---|
395 | unsigned short upper;
|
---|
396 | } l;
|
---|
397 | } CPU86_LDoubleU;
|
---|
398 |
|
---|
399 | /* the following deal with x86 long double-precision numbers */
|
---|
400 | #define MAXEXPD 0x7fff
|
---|
401 | #define EXPBIAS 16383
|
---|
402 | #define EXPD(fp) (fp.l.upper & 0x7fff)
|
---|
403 | #define SIGND(fp) ((fp.l.upper) & 0x8000)
|
---|
404 | #define MANTD(fp) (fp.l.lower)
|
---|
405 | #define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
|
---|
406 |
|
---|
407 | typedef long double floatx80;
|
---|
408 | #define STATUS_PARAM , void *pv
|
---|
409 |
|
---|
410 | static floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
|
---|
411 | {
|
---|
412 | return rintl(a);
|
---|
413 | }
|
---|
414 |
|
---|
415 |
|
---|
416 |
|
---|
417 | struct myenv
|
---|
418 | {
|
---|
419 | unsigned int fpstt; /* top of stack index */
|
---|
420 | unsigned int fpus;
|
---|
421 | unsigned int fpuc;
|
---|
422 | unsigned char fptags[8]; /* 0 = valid, 1 = empty */
|
---|
423 | union {
|
---|
424 | #ifdef USE_X86LDOUBLE
|
---|
425 | CPU86_LDouble d __attribute__((aligned(16)));
|
---|
426 | #else
|
---|
427 | CPU86_LDouble d;
|
---|
428 | #endif
|
---|
429 | } fpregs[8];
|
---|
430 |
|
---|
431 | } my_env, env_org, env_res, *env = &my_env;
|
---|
432 |
|
---|
433 |
|
---|
434 | #define ST0 (env->fpregs[env->fpstt].d)
|
---|
435 | #define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d)
|
---|
436 | #define ST1 ST(1)
|
---|
437 | #define MAXTAN 9223372036854775808.0
|
---|
438 |
|
---|
439 |
|
---|
440 | static inline void fpush(void)
|
---|
441 | {
|
---|
442 | env->fpstt = (env->fpstt - 1) & 7;
|
---|
443 | env->fptags[env->fpstt] = 0; /* validate stack entry */
|
---|
444 | }
|
---|
445 |
|
---|
446 | static inline void fpop(void)
|
---|
447 | {
|
---|
448 | env->fptags[env->fpstt] = 1; /* invalidate stack entry */
|
---|
449 | env->fpstt = (env->fpstt + 1) & 7;
|
---|
450 | }
|
---|
451 |
|
---|
452 | static void helper_f2xm1(void)
|
---|
453 | {
|
---|
454 | ST0 = pow(2.0,ST0) - 1.0;
|
---|
455 | }
|
---|
456 |
|
---|
457 | static void helper_fyl2x(void)
|
---|
458 | {
|
---|
459 | CPU86_LDouble fptemp;
|
---|
460 |
|
---|
461 | fptemp = ST0;
|
---|
462 | if (fptemp>0.0){
|
---|
463 | fptemp = log(fptemp)/log(2.0); /* log2(ST) */
|
---|
464 | ST1 *= fptemp;
|
---|
465 | fpop();
|
---|
466 | } else {
|
---|
467 | env->fpus &= (~0x4700);
|
---|
468 | env->fpus |= 0x400;
|
---|
469 | }
|
---|
470 | }
|
---|
471 |
|
---|
472 | static void helper_fptan(void)
|
---|
473 | {
|
---|
474 | CPU86_LDouble fptemp;
|
---|
475 |
|
---|
476 | fptemp = ST0;
|
---|
477 | if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
---|
478 | env->fpus |= 0x400;
|
---|
479 | } else {
|
---|
480 | ST0 = tan(fptemp);
|
---|
481 | fpush();
|
---|
482 | ST0 = 1.0;
|
---|
483 | env->fpus &= (~0x400); /* C2 <-- 0 */
|
---|
484 | /* the above code is for |arg| < 2**52 only */
|
---|
485 | }
|
---|
486 | }
|
---|
487 |
|
---|
488 | static void helper_fpatan(void)
|
---|
489 | {
|
---|
490 | CPU86_LDouble fptemp, fpsrcop;
|
---|
491 |
|
---|
492 | fpsrcop = ST1;
|
---|
493 | fptemp = ST0;
|
---|
494 | ST1 = atan2(fpsrcop,fptemp);
|
---|
495 | fpop();
|
---|
496 | }
|
---|
497 |
|
---|
498 | static void helper_fxtract(void)
|
---|
499 | {
|
---|
500 | CPU86_LDoubleU temp;
|
---|
501 | unsigned int expdif;
|
---|
502 |
|
---|
503 | temp.d = ST0;
|
---|
504 | expdif = EXPD(temp) - EXPBIAS;
|
---|
505 | /*DP exponent bias*/
|
---|
506 | ST0 = expdif;
|
---|
507 | fpush();
|
---|
508 | BIASEXPONENT(temp);
|
---|
509 | ST0 = temp.d;
|
---|
510 | }
|
---|
511 |
|
---|
512 | static void helper_fprem1(void)
|
---|
513 | {
|
---|
514 | CPU86_LDouble dblq, fpsrcop, fptemp;
|
---|
515 | CPU86_LDoubleU fpsrcop1, fptemp1;
|
---|
516 | int expdif;
|
---|
517 | int q;
|
---|
518 |
|
---|
519 | fpsrcop = ST0;
|
---|
520 | fptemp = ST1;
|
---|
521 | fpsrcop1.d = fpsrcop;
|
---|
522 | fptemp1.d = fptemp;
|
---|
523 | expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
|
---|
524 | if (expdif < 53) {
|
---|
525 | dblq = fpsrcop / fptemp;
|
---|
526 | dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
|
---|
527 | ST0 = fpsrcop - fptemp*dblq;
|
---|
528 | q = (int)dblq; /* cutting off top bits is assumed here */
|
---|
529 | env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
---|
530 | /* (C0,C1,C3) <-- (q2,q1,q0) */
|
---|
531 | env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
|
---|
532 | env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
|
---|
533 | env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
|
---|
534 | } else {
|
---|
535 | env->fpus |= 0x400; /* C2 <-- 1 */
|
---|
536 | fptemp = pow(2.0, expdif-50);
|
---|
537 | fpsrcop = (ST0 / ST1) / fptemp;
|
---|
538 | /* fpsrcop = integer obtained by rounding to the nearest */
|
---|
539 | fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
|
---|
540 | floor(fpsrcop): ceil(fpsrcop);
|
---|
541 | ST0 -= (ST1 * fpsrcop * fptemp);
|
---|
542 | }
|
---|
543 | }
|
---|
544 |
|
---|
545 | static void helper_fprem(void)
|
---|
546 | {
|
---|
547 | #if 0
|
---|
548 | LogFlow(("helper_fprem: ST0=%.*Rhxs ST1=%.*Rhxs fpus=%#x\n", sizeof(ST0), &ST0, sizeof(ST1), &ST1, env->fpus));
|
---|
549 |
|
---|
550 | __asm__ __volatile__("fldt (%2)\n"
|
---|
551 | "fldt (%1)\n"
|
---|
552 | "fprem \n"
|
---|
553 | "fnstsw (%0)\n"
|
---|
554 | "fstpt (%1)\n"
|
---|
555 | "fstpt (%2)\n"
|
---|
556 | : : "r" (&env->fpus), "r" (&ST0), "r" (&ST1) : "memory");
|
---|
557 |
|
---|
558 | LogFlow(("helper_fprem: -> ST0=%.*Rhxs fpus=%#x c\n", sizeof(ST0), &ST0, env->fpus));
|
---|
559 | #else
|
---|
560 | CPU86_LDouble dblq, fpsrcop, fptemp;
|
---|
561 | CPU86_LDoubleU fpsrcop1, fptemp1;
|
---|
562 | int expdif;
|
---|
563 | int q;
|
---|
564 |
|
---|
565 | fpsrcop = ST0;
|
---|
566 | fptemp = ST1;
|
---|
567 | fpsrcop1.d = fpsrcop;
|
---|
568 | fptemp1.d = fptemp;
|
---|
569 |
|
---|
570 | expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
|
---|
571 | if ( expdif < 53 ) {
|
---|
572 | dblq = fpsrcop / fptemp;
|
---|
573 | dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
|
---|
574 | ST0 = fpsrcop - fptemp*dblq;
|
---|
575 | q = (int)dblq; /* cutting off top bits is assumed here */
|
---|
576 | env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
---|
577 | /* (C0,C1,C3) <-- (q2,q1,q0) */
|
---|
578 | env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
|
---|
579 | env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
|
---|
580 | env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
|
---|
581 | } else {
|
---|
582 | env->fpus |= 0x400; /* C2 <-- 1 */
|
---|
583 | fptemp = pow(2.0, expdif-50);
|
---|
584 | fpsrcop = (ST0 / ST1) / fptemp;
|
---|
585 | /* fpsrcop = integer obtained by chopping */
|
---|
586 | fpsrcop = (fpsrcop < 0.0)?
|
---|
587 | -(floor(fabs(fpsrcop))): floor(fpsrcop);
|
---|
588 | ST0 -= (ST1 * fpsrcop * fptemp);
|
---|
589 | }
|
---|
590 | #endif
|
---|
591 | }
|
---|
592 |
|
---|
593 | static void helper_fyl2xp1(void)
|
---|
594 | {
|
---|
595 | CPU86_LDouble fptemp;
|
---|
596 |
|
---|
597 | fptemp = ST0;
|
---|
598 | if ((fptemp+1.0)>0.0) {
|
---|
599 | fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
|
---|
600 | ST1 *= fptemp;
|
---|
601 | fpop();
|
---|
602 | } else {
|
---|
603 | env->fpus &= (~0x4700);
|
---|
604 | env->fpus |= 0x400;
|
---|
605 | }
|
---|
606 | }
|
---|
607 |
|
---|
608 | static void helper_fsqrt(void)
|
---|
609 | {
|
---|
610 | CPU86_LDouble fptemp;
|
---|
611 |
|
---|
612 | fptemp = ST0;
|
---|
613 | if (fptemp<0.0) {
|
---|
614 | env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
---|
615 | env->fpus |= 0x400;
|
---|
616 | }
|
---|
617 | ST0 = sqrt(fptemp);
|
---|
618 | }
|
---|
619 |
|
---|
620 | static void helper_fsincos(void)
|
---|
621 | {
|
---|
622 | CPU86_LDouble fptemp;
|
---|
623 |
|
---|
624 | fptemp = ST0;
|
---|
625 | if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
---|
626 | env->fpus |= 0x400;
|
---|
627 | } else {
|
---|
628 | ST0 = sin(fptemp);
|
---|
629 | fpush();
|
---|
630 | ST0 = cos(fptemp);
|
---|
631 | env->fpus &= (~0x400); /* C2 <-- 0 */
|
---|
632 | /* the above code is for |arg| < 2**63 only */
|
---|
633 | }
|
---|
634 | }
|
---|
635 |
|
---|
636 | static void helper_frndint(void)
|
---|
637 | {
|
---|
638 | ST0 = floatx_round_to_int(ST0, &env->fp_status);
|
---|
639 | }
|
---|
640 |
|
---|
641 | static void helper_fscale(void)
|
---|
642 | {
|
---|
643 | ST0 = ldexp (ST0, (int)(ST1));
|
---|
644 | }
|
---|
645 |
|
---|
646 | static void helper_fsin(void)
|
---|
647 | {
|
---|
648 | CPU86_LDouble fptemp;
|
---|
649 |
|
---|
650 | fptemp = ST0;
|
---|
651 | if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
---|
652 | env->fpus |= 0x400;
|
---|
653 | } else {
|
---|
654 | ST0 = sin(fptemp);
|
---|
655 | env->fpus &= (~0x400); /* C2 <-- 0 */
|
---|
656 | /* the above code is for |arg| < 2**53 only */
|
---|
657 | }
|
---|
658 | }
|
---|
659 |
|
---|
660 | static void helper_fcos(void)
|
---|
661 | {
|
---|
662 | CPU86_LDouble fptemp;
|
---|
663 |
|
---|
664 | fptemp = ST0;
|
---|
665 | if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
|
---|
666 | env->fpus |= 0x400;
|
---|
667 | } else {
|
---|
668 | ST0 = cos(fptemp);
|
---|
669 | env->fpus &= (~0x400); /* C2 <-- 0 */
|
---|
670 | /* the above code is for |arg5 < 2**63 only */
|
---|
671 | }
|
---|
672 | }
|
---|
673 |
|
---|
674 | static void helper_fxam_ST0(void)
|
---|
675 | {
|
---|
676 | CPU86_LDoubleU temp;
|
---|
677 | int expdif;
|
---|
678 |
|
---|
679 | temp.d = ST0;
|
---|
680 |
|
---|
681 | env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
|
---|
682 | if (SIGND(temp))
|
---|
683 | env->fpus |= 0x200; /* C1 <-- 1 */
|
---|
684 |
|
---|
685 | /* XXX: test fptags too */
|
---|
686 | expdif = EXPD(temp);
|
---|
687 | if (expdif == MAXEXPD) {
|
---|
688 | #ifdef USE_X86LDOUBLE
|
---|
689 | if (MANTD(temp) == 0x8000000000000000ULL)
|
---|
690 | #else
|
---|
691 | if (MANTD(temp) == 0)
|
---|
692 | #endif
|
---|
693 | env->fpus |= 0x500 /*Infinity*/;
|
---|
694 | else
|
---|
695 | env->fpus |= 0x100 /*NaN*/;
|
---|
696 | } else if (expdif == 0) {
|
---|
697 | if (MANTD(temp) == 0)
|
---|
698 | env->fpus |= 0x4000 /*Zero*/;
|
---|
699 | else
|
---|
700 | env->fpus |= 0x4400 /*Denormal*/;
|
---|
701 | } else {
|
---|
702 | env->fpus |= 0x400;
|
---|
703 | }
|
---|
704 | }
|
---|
705 |
|
---|
706 |
|
---|
707 | void check_env(void)
|
---|
708 | {
|
---|
709 | int i;
|
---|
710 | for (i = 0; i < 8; i++)
|
---|
711 | {
|
---|
712 | CPU86_LDoubleU my, res;
|
---|
713 | my.d = env->fpregs[i].d;
|
---|
714 | res.d = env_res.fpregs[i].d;
|
---|
715 |
|
---|
716 | if ( my.l.lower != res.l.lower
|
---|
717 | || my.l.upper != res.l.upper)
|
---|
718 | printf("register %i: %#018llx:%#06x\n"
|
---|
719 | " expected %#018llx:%#06x\n",
|
---|
720 | i,
|
---|
721 | my.l.lower, my.l.upper,
|
---|
722 | res.l.lower, res.l.upper);
|
---|
723 | }
|
---|
724 | for (i = 0; i < 8; i++)
|
---|
725 | if (env->fptags[i] != env_res.fptags[i])
|
---|
726 | printf("tag %i: %d != %d\n", i, env->fptags[i], env_res.fptags[i]);
|
---|
727 | if (env->fpstt != env_res.fpstt)
|
---|
728 | printf("fpstt: %#06x != %#06x\n", env->fpstt, env_res.fpstt);
|
---|
729 | if (env->fpuc != env_res.fpuc)
|
---|
730 | printf("fpuc: %#06x != %#06x\n", env->fpuc, env_res.fpuc);
|
---|
731 | if (env->fpus != env_res.fpus)
|
---|
732 | printf("fpus: %#06x != %#06x\n", env->fpus, env_res.fpus);
|
---|
733 | }
|
---|
734 | #endif /* not used. */
|
---|
735 |
|
---|
736 | #if 0 /* insert this into helper.c */
|
---|
737 | /* FPU helpers */
|
---|
738 | CPU86_LDoubleU my_st[8];
|
---|
739 | unsigned int my_fpstt;
|
---|
740 | unsigned int my_fpus;
|
---|
741 | unsigned int my_fpuc;
|
---|
742 | unsigned char my_fptags[8];
|
---|
743 |
|
---|
744 | void hlp_fpu_enter(void)
|
---|
745 | {
|
---|
746 | int i;
|
---|
747 | for (i = 0; i < 8; i++)
|
---|
748 | my_st[i].d = env->fpregs[i].d;
|
---|
749 | my_fpstt = env->fpstt;
|
---|
750 | my_fpus = env->fpus;
|
---|
751 | my_fpuc = env->fpuc;
|
---|
752 | memcpy(&my_fptags, &env->fptags, sizeof(my_fptags));
|
---|
753 | }
|
---|
754 |
|
---|
755 | void hlp_fpu_leave(const char *psz)
|
---|
756 | {
|
---|
757 | int i;
|
---|
758 | Log(("/*code*/ \n"));
|
---|
759 | for (i = 0; i < 8; i++)
|
---|
760 | Log(("/*code*/ *(unsigned long long *)&env_org.fpregs[%d] = %#018llxULL; ((unsigned short *)&env_org.fpregs[%d])[4] = %#06x; env_org.fptags[%d]=%d;\n",
|
---|
761 | i, my_st[i].l.lower, i, my_st[i].l.upper, i, my_fptags[i]));
|
---|
762 | Log(("/*code*/ env_org.fpstt=%#x;\n", my_fpstt));
|
---|
763 | Log(("/*code*/ env_org.fpus=%#x;\n", my_fpus));
|
---|
764 | Log(("/*code*/ env_org.fpuc=%#x;\n", my_fpuc));
|
---|
765 | for (i = 0; i < 8; i++)
|
---|
766 | {
|
---|
767 | CPU86_LDoubleU u;
|
---|
768 | u.d = env->fpregs[i].d;
|
---|
769 | Log(("/*code*/ *(unsigned long long *)&env_res.fpregs[%d] = %#018llxULL; ((unsigned short *)&env_res.fpregs[%d])[4] = %#06x; env_res.fptags[%d]=%d;\n",
|
---|
770 | i, u.l.lower, i, u.l.upper, i, env->fptags[i]));
|
---|
771 | }
|
---|
772 | Log(("/*code*/ env_res.fpstt=%#x;\n", env->fpstt));
|
---|
773 | Log(("/*code*/ env_res.fpus=%#x;\n", env->fpus));
|
---|
774 | Log(("/*code*/ env_res.fpuc=%#x;\n", env->fpuc));
|
---|
775 |
|
---|
776 | Log(("/*code*/ my_env = env_org;\n"));
|
---|
777 | Log(("/*code*/ %s();\n", psz));
|
---|
778 | Log(("/*code*/ check_env();\n"));
|
---|
779 | }
|
---|
780 | #endif /* helper.c */
|
---|
781 |
|
---|
782 | extern void testmath2(void )
|
---|
783 | {
|
---|
784 | #if 0
|
---|
785 | #include "/tmp/code.h"
|
---|
786 | #endif
|
---|
787 | }
|
---|
788 |
|
---|
789 |
|
---|
790 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
791 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
792 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
793 |
|
---|
794 | #ifdef MATHTEST_STANDALONE
|
---|
795 |
|
---|
796 | void test_fops(double a, double b)
|
---|
797 | {
|
---|
798 | printf("a=%f b=%f a+b=%f\n", a, b, a + b);
|
---|
799 | printf("a=%f b=%f a-b=%f\n", a, b, a - b);
|
---|
800 | printf("a=%f b=%f a*b=%f\n", a, b, a * b);
|
---|
801 | printf("a=%f b=%f a/b=%f\n", a, b, a / b);
|
---|
802 | printf("a=%f b=%f fmod(a, b)=%f\n", a, b, (double)fmod(a, b));
|
---|
803 | printf("a=%f sqrt(a)=%f\n", a, (double)sqrtl(a));
|
---|
804 | printf("a=%f sin(a)=%f\n", a, (double)sinl(a));
|
---|
805 | printf("a=%f cos(a)=%f\n", a, (double)cos(a));
|
---|
806 | printf("a=%f tan(a)=%f\n", a, (double)tanl(a));
|
---|
807 | printf("a=%f log(a)=%f\n", a, (double)log(a));
|
---|
808 | printf("a=%f exp(a)=%f\n", a, (double)exp(a));
|
---|
809 | printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b));
|
---|
810 | /* just to test some op combining */
|
---|
811 | printf("a=%f asin(sinl(a))=%f\n", a, (double)asin(sinl(a)));
|
---|
812 | printf("a=%f acos(cos(a))=%f\n", a, (double)acos(cos(a)));
|
---|
813 | printf("a=%f atan(tanl(a))=%f\n", a, (double)atan(tanl(a)));
|
---|
814 | }
|
---|
815 |
|
---|
816 | int main()
|
---|
817 | {
|
---|
818 | unsigned cErrors = testmath();
|
---|
819 |
|
---|
820 | testmath2();
|
---|
821 | test_fops(2, 3);
|
---|
822 | test_fops(1.4, -5);
|
---|
823 |
|
---|
824 | printf("cErrors=%u\n", cErrors);
|
---|
825 | return cErrors;
|
---|
826 | }
|
---|
827 | #endif
|
---|
828 |
|
---|