msvcrt: Use fpclass constants from public header.
[wine/zf.git] / dlls / msvcrt / math.c
blobb7a62d9cf2c6330bd5d2e68a58d742a4f2fa8cb2
1 /*
2 * msvcrt.dll math functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * For functions copied from musl libc (http://musl.libc.org/):
22 * ====================================================
23 * Copyright 2005-2020 Rich Felker, et al.
25 * Permission is hereby granted, free of charge, to any person obtaining
26 * a copy of this software and associated documentation files (the
27 * "Software"), to deal in the Software without restriction, including
28 * without limitation the rights to use, copy, modify, merge, publish,
29 * distribute, sublicense, and/or sell copies of the Software, and to
30 * permit persons to whom the Software is furnished to do so, subject to
31 * the following conditions:
33 * The above copyright notice and this permission notice shall be
34 * included in all copies or substantial portions of the Software.
35 * ====================================================
39 #include <stdio.h>
40 #include <fenv.h>
41 #include <fpieee.h>
42 #include <limits.h>
43 #include <locale.h>
44 #include <math.h>
46 #include "msvcrt.h"
47 #include "winternl.h"
48 #include "unixlib.h"
50 #include "wine/asm.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
55 #define _DOMAIN 1 /* domain error in argument */
56 #define _SING 2 /* singularity */
57 #define _OVERFLOW 3 /* range overflow */
58 #define _UNDERFLOW 4 /* range underflow */
60 typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *);
61 typedef double LDOUBLE; /* long double is just a double */
63 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
65 static BOOL sse2_supported;
66 static BOOL sse2_enabled;
68 static const struct unix_funcs *unix_funcs;
70 void msvcrt_init_math( void *module )
72 sse2_supported = sse2_enabled = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
73 __wine_init_unix_lib( module, DLL_PROCESS_ATTACH, NULL, &unix_funcs );
76 /* Copied from musl: src/internal/libm.h */
77 static inline float fp_barrierf(float x)
79 volatile float y = x;
80 return y;
83 /*********************************************************************
84 * _matherr (CRTDLL.@)
86 int CDECL MSVCRT__matherr(struct _exception *e)
88 return 0;
92 static double math_error(int type, const char *name, double arg1, double arg2, double retval)
94 struct _exception exception = {type, (char *)name, arg1, arg2, retval};
96 TRACE("(%d, %s, %g, %g, %g)\n", type, debugstr_a(name), arg1, arg2, retval);
98 if (MSVCRT_default_matherr_func && MSVCRT_default_matherr_func(&exception))
99 return exception.retval;
101 switch (type)
103 case _DOMAIN:
104 *_errno() = EDOM;
105 break;
106 case _SING:
107 case _OVERFLOW:
108 *_errno() = ERANGE;
109 break;
110 case _UNDERFLOW:
111 /* don't set errno */
112 break;
113 default:
114 ERR("Unhandled math error!\n");
117 return exception.retval;
120 /*********************************************************************
121 * __setusermatherr (MSVCRT.@)
123 void CDECL MSVCRT___setusermatherr(MSVCRT_matherr_func func)
125 MSVCRT_default_matherr_func = func;
126 TRACE("new matherr handler %p\n", func);
129 /*********************************************************************
130 * _set_SSE2_enable (MSVCRT.@)
132 int CDECL MSVCRT__set_SSE2_enable(int flag)
134 sse2_enabled = flag && sse2_supported;
135 return sse2_enabled;
138 #if defined(_WIN64)
139 # if _MSVCR_VER>=140
140 /*********************************************************************
141 * _get_FMA3_enable (UCRTBASE.@)
143 int CDECL MSVCRT__get_FMA3_enable(void)
145 FIXME("() stub\n");
146 return 0;
148 # endif
150 # if _MSVCR_VER>=120
151 /*********************************************************************
152 * _set_FMA3_enable (MSVCR120.@)
154 int CDECL MSVCRT__set_FMA3_enable(int flag)
156 FIXME("(%x) stub\n", flag);
157 return 0;
159 # endif
160 #endif
162 #if !defined(__i386__) || _MSVCR_VER>=120
164 /*********************************************************************
165 * _chgsignf (MSVCRT.@)
167 float CDECL MSVCRT__chgsignf( float num )
169 union { float f; UINT32 i; } u = { num };
170 u.i ^= 0x80000000;
171 return u.f;
174 /*********************************************************************
175 * _copysignf (MSVCRT.@)
177 * Copied from musl: src/math/copysignf.c
179 float CDECL MSVCRT__copysignf( float x, float y )
181 union { float f; UINT32 i; } ux = { x }, uy = { y };
182 ux.i &= 0x7fffffff;
183 ux.i |= uy.i & 0x80000000;
184 return ux.f;
187 /*********************************************************************
188 * _nextafterf (MSVCRT.@)
190 float CDECL MSVCRT__nextafterf( float num, float next )
192 if (!isfinite(num) || !isfinite(next)) *_errno() = EDOM;
193 return unix_funcs->nextafterf( num, next );
196 /*********************************************************************
197 * _logbf (MSVCRT.@)
199 float CDECL MSVCRT__logbf( float num )
201 float ret = unix_funcs->logbf(num);
202 if (isnan(num)) return math_error(_DOMAIN, "_logbf", num, 0, ret);
203 if (!num) return math_error(_SING, "_logbf", num, 0, ret);
204 return ret;
207 #endif
209 /*********************************************************************
210 * _fpclassf (MSVCRT.@)
212 int CDECL MSVCRT__fpclassf( float num )
214 union { float f; UINT32 i; } u = { num };
215 int e = u.i >> 23 & 0xff;
216 int s = u.i >> 31;
218 switch (e)
220 case 0:
221 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
222 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
223 case 0xff:
224 if (u.i << 9) return ((u.i >> 22) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
225 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
226 default:
227 return s ? _FPCLASS_NN : _FPCLASS_PN;
231 /*********************************************************************
232 * _finitef (MSVCRT.@)
234 int CDECL MSVCRT__finitef( float num )
236 union { float f; UINT32 i; } u = { num };
237 return (u.i & 0x7fffffff) < 0x7f800000;
240 /*********************************************************************
241 * _isnanf (MSVCRT.@)
243 int CDECL MSVCRT__isnanf( float num )
245 union { float f; UINT32 i; } u = { num };
246 return (u.i & 0x7fffffff) > 0x7f800000;
249 /*********************************************************************
250 * MSVCRT_acosf (MSVCRT.@)
252 * Copied from musl: src/math/acosf.c
254 static float acosf_R(float z)
256 static const float pS0 = 1.6666586697e-01,
257 pS1 = -4.2743422091e-02,
258 pS2 = -8.6563630030e-03,
259 qS1 = -7.0662963390e-01;
261 float p, q;
262 p = z * (pS0 + z * (pS1 + z * pS2));
263 q = 1.0f + z * qS1;
264 return p / q;
267 float CDECL MSVCRT_acosf( float x )
269 static const float pio2_hi = 1.5707962513e+00,
270 pio2_lo = 7.5497894159e-08;
272 float z, w, s, c, df;
273 unsigned int hx, ix;
275 hx = *(unsigned int*)&x;
276 ix = hx & 0x7fffffff;
277 /* |x| >= 1 or nan */
278 if (ix >= 0x3f800000) {
279 if (ix == 0x3f800000) {
280 if (hx >> 31)
281 return 2 * pio2_lo + 2 * pio2_hi + 7.5231638453e-37;
282 return 0;
284 if (isnan(x)) return x;
285 return math_error(_DOMAIN, "acosf", x, 0, 0 / (x - x));
287 /* |x| < 0.5 */
288 if (ix < 0x3f000000) {
289 if (ix <= 0x32800000) /* |x| < 2**-26 */
290 return pio2_lo + pio2_hi + 7.5231638453e-37;
291 return pio2_hi - (x - (pio2_lo - x * acosf_R(x * x)));
293 /* x < -0.5 */
294 if (hx >> 31) {
295 z = (1 + x) * 0.5f;
296 s = MSVCRT_sqrtf(z);
297 w = acosf_R(z) * s - pio2_lo;
298 return 2 * (pio2_hi - (s + w));
300 /* x > 0.5 */
301 z = (1 - x) * 0.5f;
302 s = MSVCRT_sqrtf(z);
303 hx = *(unsigned int*)&s & 0xfffff000;
304 df = *(float*)&hx;
305 c = (z - df * df) / (s + df);
306 w = acosf_R(z) * s + c;
307 return 2 * (df + w);
310 /*********************************************************************
311 * MSVCRT_asinf (MSVCRT.@)
313 * Copied from musl: src/math/asinf.c
315 static float asinf_R(float z)
317 /* coefficients for R(x^2) */
318 static const float pS0 = 1.6666586697e-01,
319 pS1 = -4.2743422091e-02,
320 pS2 = -8.6563630030e-03,
321 qS1 = -7.0662963390e-01;
323 float p, q;
324 p = z * (pS0 + z * (pS1 + z * pS2));
325 q = 1.0f + z * qS1;
326 return p / q;
329 float CDECL MSVCRT_asinf( float x )
331 static const double pio2 = 1.570796326794896558e+00;
333 double s;
334 float z;
335 unsigned int hx, ix;
337 hx = *(unsigned int*)&x;
338 ix = hx & 0x7fffffff;
339 if (ix >= 0x3f800000) { /* |x| >= 1 */
340 if (ix == 0x3f800000) /* |x| == 1 */
341 return x * pio2 + 7.5231638453e-37; /* asin(+-1) = +-pi/2 with inexact */
342 if (isnan(x)) return x;
343 return math_error(_DOMAIN, "asinf", x, 0, 0 / (x - x));
345 if (ix < 0x3f000000) { /* |x| < 0.5 */
346 /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
347 if (ix < 0x39800000 && ix >= 0x00800000)
348 return x;
349 return x + x * asinf_R(x * x);
351 /* 1 > |x| >= 0.5 */
352 z = (1 - fabsf(x)) * 0.5f;
353 s = MSVCRT_sqrt(z);
354 x = pio2 - 2 * (s + s * asinf_R(z));
355 if (hx >> 31)
356 return -x;
357 return x;
360 /*********************************************************************
361 * MSVCRT_atanf (MSVCRT.@)
363 * Copied from musl: src/math/atanf.c
365 float CDECL MSVCRT_atanf( float x )
367 static const float atanhi[] = {
368 4.6364760399e-01,
369 7.8539812565e-01,
370 9.8279368877e-01,
371 1.5707962513e+00,
373 static const float atanlo[] = {
374 5.0121582440e-09,
375 3.7748947079e-08,
376 3.4473217170e-08,
377 7.5497894159e-08,
379 static const float aT[] = {
380 3.3333328366e-01,
381 -1.9999158382e-01,
382 1.4253635705e-01,
383 -1.0648017377e-01,
384 6.1687607318e-02,
387 float w, s1, s2, z;
388 unsigned int ix, sign;
389 int id;
391 #if _MSVCR_VER == 0
392 if (isnan(x)) return math_error(_DOMAIN, "atanf", x, 0, x);
393 #endif
395 ix = *(unsigned int*)&x;
396 sign = ix >> 31;
397 ix &= 0x7fffffff;
398 if (ix >= 0x4c800000) { /* if |x| >= 2**26 */
399 if (isnan(x))
400 return x;
401 z = atanhi[3] + 7.5231638453e-37;
402 return sign ? -z : z;
404 if (ix < 0x3ee00000) { /* |x| < 0.4375 */
405 if (ix < 0x39800000) { /* |x| < 2**-12 */
406 if (ix < 0x00800000)
407 /* raise underflow for subnormal x */
408 fp_barrierf(x*x);
409 return x;
411 id = -1;
412 } else {
413 x = fabsf(x);
414 if (ix < 0x3f980000) { /* |x| < 1.1875 */
415 if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */
416 id = 0;
417 x = (2.0f * x - 1.0f) / (2.0f + x);
418 } else { /* 11/16 <= |x| < 19/16 */
419 id = 1;
420 x = (x - 1.0f) / (x + 1.0f);
422 } else {
423 if (ix < 0x401c0000) { /* |x| < 2.4375 */
424 id = 2;
425 x = (x - 1.5f) / (1.0f + 1.5f * x);
426 } else { /* 2.4375 <= |x| < 2**26 */
427 id = 3;
428 x = -1.0f / x;
432 /* end of argument reduction */
433 z = x * x;
434 w = z * z;
435 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
436 s1 = z * (aT[0] + w * (aT[2] + w * aT[4]));
437 s2 = w * (aT[1] + w * aT[3]);
438 if (id < 0)
439 return x - x * (s1 + s2);
440 z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x);
441 return sign ? -z : z;
444 /*********************************************************************
445 * MSVCRT_atan2f (MSVCRT.@)
447 * Copied from musl: src/math/atan2f.c
449 float CDECL MSVCRT_atan2f( float y, float x )
451 static const float pi = 3.1415927410e+00,
452 pi_lo = -8.7422776573e-08;
454 float z;
455 unsigned int m, ix, iy;
457 if (isnan(x) || isnan(y))
458 return x + y;
459 ix = *(unsigned int*)&x;
460 iy = *(unsigned int*)&y;
461 if (ix == 0x3f800000) /* x=1.0 */
462 return MSVCRT_atanf(y);
463 m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
464 ix &= 0x7fffffff;
465 iy &= 0x7fffffff;
467 /* when y = 0 */
468 if (iy == 0) {
469 switch (m) {
470 case 0:
471 case 1: return y; /* atan(+-0,+anything)=+-0 */
472 case 2: return pi; /* atan(+0,-anything) = pi */
473 case 3: return -pi; /* atan(-0,-anything) =-pi */
476 /* when x = 0 */
477 if (ix == 0)
478 return m & 1 ? -pi / 2 : pi / 2;
479 /* when x is INF */
480 if (ix == 0x7f800000) {
481 if (iy == 0x7f800000) {
482 switch (m) {
483 case 0: return pi / 4; /* atan(+INF,+INF) */
484 case 1: return -pi / 4; /* atan(-INF,+INF) */
485 case 2: return 3 * pi / 4; /*atan(+INF,-INF)*/
486 case 3: return -3 * pi / 4; /*atan(-INF,-INF)*/
488 } else {
489 switch (m) {
490 case 0: return 0.0f; /* atan(+...,+INF) */
491 case 1: return -0.0f; /* atan(-...,+INF) */
492 case 2: return pi; /* atan(+...,-INF) */
493 case 3: return -pi; /* atan(-...,-INF) */
497 /* |y/x| > 0x1p26 */
498 if (ix + (26 << 23) < iy || iy == 0x7f800000)
499 return m & 1 ? -pi / 2 : pi / 2;
501 /* z = atan(|y/x|) with correct underflow */
502 if ((m & 2) && iy + (26 << 23) < ix) /*|y/x| < 0x1p-26, x < 0 */
503 z = 0.0;
504 else
505 z = MSVCRT_atanf(fabsf(y / x));
506 switch (m) {
507 case 0: return z; /* atan(+,+) */
508 case 1: return -z; /* atan(-,+) */
509 case 2: return pi - (z - pi_lo); /* atan(+,-) */
510 default: /* case 3 */
511 return (z - pi_lo) - pi; /* atan(-,-) */
515 /*********************************************************************
516 * MSVCRT_cosf (MSVCRT.@)
518 float CDECL MSVCRT_cosf( float x )
520 float ret = unix_funcs->cosf( x );
521 if (!isfinite(x)) return math_error(_DOMAIN, "cosf", x, 0, ret);
522 return ret;
525 /*********************************************************************
526 * MSVCRT_coshf (MSVCRT.@)
528 float CDECL MSVCRT_coshf( float x )
530 float ret = unix_funcs->coshf( x );
531 if (isnan(x)) return math_error(_DOMAIN, "coshf", x, 0, ret);
532 return ret;
535 /*********************************************************************
536 * MSVCRT_expf (MSVCRT.@)
538 float CDECL MSVCRT_expf( float x )
540 float ret = unix_funcs->expf( x );
541 if (isnan(x)) return math_error(_DOMAIN, "expf", x, 0, ret);
542 if (isfinite(x) && !ret) return math_error(_UNDERFLOW, "expf", x, 0, ret);
543 if (isfinite(x) && !isfinite(ret)) return math_error(_OVERFLOW, "expf", x, 0, ret);
544 return ret;
547 /*********************************************************************
548 * MSVCRT_fmodf (MSVCRT.@)
550 float CDECL MSVCRT_fmodf( float x, float y )
552 float ret = unix_funcs->fmodf( x, y );
553 if (!isfinite(x) || !isfinite(y)) return math_error(_DOMAIN, "fmodf", x, 0, ret);
554 return ret;
557 /*********************************************************************
558 * MSVCRT_logf (MSVCRT.@)
560 float CDECL MSVCRT_logf( float x )
562 float ret = unix_funcs->logf( x );
563 if (x < 0.0) return math_error(_DOMAIN, "logf", x, 0, ret);
564 if (x == 0.0) return math_error(_SING, "logf", x, 0, ret);
565 return ret;
568 /*********************************************************************
569 * MSVCRT_log10f (MSVCRT.@)
571 float CDECL MSVCRT_log10f( float x )
573 float ret = unix_funcs->log10f( x );
574 if (x < 0.0) return math_error(_DOMAIN, "log10f", x, 0, ret);
575 if (x == 0.0) return math_error(_SING, "log10f", x, 0, ret);
576 return ret;
579 /*********************************************************************
580 * MSVCRT_powf (MSVCRT.@)
582 float CDECL MSVCRT_powf( float x, float y )
584 float z = unix_funcs->powf(x,y);
585 if (x < 0 && y != MSVCRT_floorf(y)) return math_error(_DOMAIN, "powf", x, y, z);
586 if (!x && isfinite(y) && y < 0) return math_error(_SING, "powf", x, y, z);
587 if (isfinite(x) && isfinite(y) && !isfinite(z)) return math_error(_OVERFLOW, "powf", x, y, z);
588 if (x && isfinite(x) && isfinite(y) && !z) return math_error(_UNDERFLOW, "powf", x, y, z);
589 return z;
592 /*********************************************************************
593 * MSVCRT_sinf (MSVCRT.@)
595 float CDECL MSVCRT_sinf( float x )
597 float ret = unix_funcs->sinf( x );
598 if (!isfinite(x)) return math_error(_DOMAIN, "sinf", x, 0, ret);
599 return ret;
602 /*********************************************************************
603 * MSVCRT_sinhf (MSVCRT.@)
605 float CDECL MSVCRT_sinhf( float x )
607 float ret = unix_funcs->sinhf( x );
608 if (isnan(x)) return math_error(_DOMAIN, "sinhf", x, 0, ret);
609 return ret;
612 /*********************************************************************
613 * MSVCRT_sqrtf (MSVCRT.@)
615 * Copied from musl: src/math/sqrtf.c
617 float CDECL MSVCRT_sqrtf( float x )
619 static const float tiny = 1.0e-30;
621 float z;
622 int sign = 0x80000000;
623 int ix,s,q,m,t,i;
624 unsigned int r;
626 ix = *(int*)&x;
628 /* take care of Inf and NaN */
629 if ((ix & 0x7f800000) == 0x7f800000 && (ix == 0x7f800000 || ix & 0x7fffff))
630 return x;
632 /* take care of zero */
633 if (ix <= 0) {
634 if ((ix & ~sign) == 0)
635 return x; /* sqrt(+-0) = +-0 */
636 return math_error(_DOMAIN, "sqrtf", x, 0, (x - x) / (x - x)); /* sqrt(-ve) = sNaN */
638 /* normalize x */
639 m = ix >> 23;
640 if (m == 0) { /* subnormal x */
641 for (i = 0; (ix & 0x00800000) == 0; i++)
642 ix <<= 1;
643 m -= i - 1;
645 m -= 127; /* unbias exponent */
646 ix = (ix & 0x007fffff) | 0x00800000;
647 if (m & 1) /* odd m, double x to make it even */
648 ix += ix;
649 m >>= 1; /* m = [m/2] */
651 /* generate sqrt(x) bit by bit */
652 ix += ix;
653 q = s = 0; /* q = sqrt(x) */
654 r = 0x01000000; /* r = moving bit from right to left */
656 while (r != 0) {
657 t = s + r;
658 if (t <= ix) {
659 s = t + r;
660 ix -= t;
661 q += r;
663 ix += ix;
664 r >>= 1;
667 /* use floating add to find out rounding direction */
668 if (ix != 0) {
669 z = 1.0f - tiny; /* raise inexact flag */
670 if (z >= 1.0f) {
671 z = 1.0f + tiny;
672 if (z > 1.0f)
673 q += 2;
674 else
675 q += q & 1;
678 ix = (q >> 1) + 0x3f000000;
679 r = ix + ((unsigned int)m << 23);
680 z = *(float*)&r;
681 return z;
684 /*********************************************************************
685 * MSVCRT_tanf (MSVCRT.@)
687 float CDECL MSVCRT_tanf( float x )
689 float ret = unix_funcs->tanf(x);
690 if (!isfinite(x)) return math_error(_DOMAIN, "tanf", x, 0, ret);
691 return ret;
694 /*********************************************************************
695 * MSVCRT_tanhf (MSVCRT.@)
697 float CDECL MSVCRT_tanhf( float x )
699 float ret = unix_funcs->tanhf(x);
700 if (!isfinite(x)) return math_error(_DOMAIN, "tanhf", x, 0, ret);
701 return ret;
704 /*********************************************************************
705 * ceilf (MSVCRT.@)
707 float CDECL MSVCRT_ceilf( float x )
709 return unix_funcs->ceilf(x);
712 /*********************************************************************
713 * fabsf (MSVCRT.@)
715 * Copied from musl: src/math/fabsf.c
717 float CDECL MSVCRT_fabsf( float x )
719 union { float f; UINT32 i; } u = { x };
720 u.i &= 0x7fffffff;
721 return u.f;
724 /*********************************************************************
725 * floorf (MSVCRT.@)
727 float CDECL MSVCRT_floorf( float x )
729 return unix_funcs->floorf(x);
732 /*********************************************************************
733 * frexpf (MSVCRT.@)
735 float CDECL MSVCRT_frexpf( float x, int *exp )
737 return unix_funcs->frexpf( x, exp );
740 /*********************************************************************
741 * modff (MSVCRT.@)
743 float CDECL MSVCRT_modff( float x, float *iptr )
745 return unix_funcs->modff( x, iptr );
748 /*********************************************************************
749 * MSVCRT_acos (MSVCRT.@)
751 * Copied from musl: src/math/acos.c
753 static double acos_R(double z)
755 static const double pS0 = 1.66666666666666657415e-01,
756 pS1 = -3.25565818622400915405e-01,
757 pS2 = 2.01212532134862925881e-01,
758 pS3 = -4.00555345006794114027e-02,
759 pS4 = 7.91534994289814532176e-04,
760 pS5 = 3.47933107596021167570e-05,
761 qS1 = -2.40339491173441421878e+00,
762 qS2 = 2.02094576023350569471e+00,
763 qS3 = -6.88283971605453293030e-01,
764 qS4 = 7.70381505559019352791e-02;
766 double p, q;
767 p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
768 q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
769 return p/q;
772 double CDECL MSVCRT_acos( double x )
774 static const double pio2_hi = 1.57079632679489655800e+00,
775 pio2_lo = 6.12323399573676603587e-17;
777 double z, w, s, c, df;
778 unsigned int hx, ix;
779 ULONGLONG llx;
781 hx = *(ULONGLONG*)&x >> 32;
782 ix = hx & 0x7fffffff;
783 /* |x| >= 1 or nan */
784 if (ix >= 0x3ff00000) {
785 unsigned int lx;
787 lx = *(ULONGLONG*)&x;
788 if (((ix - 0x3ff00000) | lx) == 0) {
789 /* acos(1)=0, acos(-1)=pi */
790 if (hx >> 31)
791 return 2 * pio2_hi + 7.5231638452626401e-37;
792 return 0;
794 if (isnan(x)) return x;
795 return math_error(_DOMAIN, "acos", x, 0, 0 / (x - x));
797 /* |x| < 0.5 */
798 if (ix < 0x3fe00000) {
799 if (ix <= 0x3c600000) /* |x| < 2**-57 */
800 return pio2_hi + 7.5231638452626401e-37;
801 return pio2_hi - (x - (pio2_lo - x * acos_R(x * x)));
803 /* x < -0.5 */
804 if (hx >> 31) {
805 z = (1.0 + x) * 0.5;
806 s = MSVCRT_sqrt(z);
807 w = acos_R(z) * s - pio2_lo;
808 return 2 * (pio2_hi - (s + w));
810 /* x > 0.5 */
811 z = (1.0 - x) * 0.5;
812 s = MSVCRT_sqrt(z);
813 df = s;
814 llx = (*(ULONGLONG*)&df >> 32) << 32;
815 df = *(double*)&llx;
816 c = (z - df * df) / (s + df);
817 w = acos_R(z) * s + c;
818 return 2 * (df + w);
821 /*********************************************************************
822 * MSVCRT_asin (MSVCRT.@)
824 * Copied from musl: src/math/asin.c
826 static double asin_R(double z)
828 /* coefficients for R(x^2) */
829 static const double pS0 = 1.66666666666666657415e-01,
830 pS1 = -3.25565818622400915405e-01,
831 pS2 = 2.01212532134862925881e-01,
832 pS3 = -4.00555345006794114027e-02,
833 pS4 = 7.91534994289814532176e-04,
834 pS5 = 3.47933107596021167570e-05,
835 qS1 = -2.40339491173441421878e+00,
836 qS2 = 2.02094576023350569471e+00,
837 qS3 = -6.88283971605453293030e-01,
838 qS4 = 7.70381505559019352791e-02;
840 double p, q;
841 p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
842 q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
843 return p / q;
846 double CDECL MSVCRT_asin( double x )
848 static const double pio2_hi = 1.57079632679489655800e+00,
849 pio2_lo = 6.12323399573676603587e-17;
851 double z, r, s;
852 unsigned int hx, ix;
853 ULONGLONG llx;
855 hx = *(ULONGLONG*)&x >> 32;
856 ix = hx & 0x7fffffff;
857 /* |x| >= 1 or nan */
858 if (ix >= 0x3ff00000) {
859 unsigned int lx;
860 lx = *(ULONGLONG*)&x;
861 if (((ix - 0x3ff00000) | lx) == 0)
862 /* asin(1) = +-pi/2 with inexact */
863 return x * pio2_hi + 7.5231638452626401e-37;
864 if (isnan(x)) return x;
865 return math_error(_DOMAIN, "asin", x, 0, 0 / (x - x));
867 /* |x| < 0.5 */
868 if (ix < 0x3fe00000) {
869 /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
870 if (ix < 0x3e500000 && ix >= 0x00100000)
871 return x;
872 return x + x * asin_R(x * x);
874 /* 1 > |x| >= 0.5 */
875 z = (1 - fabs(x)) * 0.5;
876 s = MSVCRT_sqrt(z);
877 r = asin_R(z);
878 if (ix >= 0x3fef3333) { /* if |x| > 0.975 */
879 x = pio2_hi - (2 * (s + s * r) - pio2_lo);
880 } else {
881 double f, c;
882 /* f+c = sqrt(z) */
883 f = s;
884 llx = (*(ULONGLONG*)&f >> 32) << 32;
885 f = *(double*)&llx;
886 c = (z - f * f) / (s + f);
887 x = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * f));
889 if (hx >> 31)
890 return -x;
891 return x;
894 /*********************************************************************
895 * MSVCRT_atan (MSVCRT.@)
897 * Copied from musl: src/math/atan.c
899 double CDECL MSVCRT_atan( double x )
901 static const double atanhi[] = {
902 4.63647609000806093515e-01,
903 7.85398163397448278999e-01,
904 9.82793723247329054082e-01,
905 1.57079632679489655800e+00,
907 static const double atanlo[] = {
908 2.26987774529616870924e-17,
909 3.06161699786838301793e-17,
910 1.39033110312309984516e-17,
911 6.12323399573676603587e-17,
913 static const double aT[] = {
914 3.33333333333329318027e-01,
915 -1.99999999998764832476e-01,
916 1.42857142725034663711e-01,
917 -1.11111104054623557880e-01,
918 9.09088713343650656196e-02,
919 -7.69187620504482999495e-02,
920 6.66107313738753120669e-02,
921 -5.83357013379057348645e-02,
922 4.97687799461593236017e-02,
923 -3.65315727442169155270e-02,
924 1.62858201153657823623e-02,
927 double w, s1, s2, z;
928 unsigned int ix, sign;
929 int id;
931 #if _MSVCR_VER == 0
932 if (isnan(x)) return math_error(_DOMAIN, "atan", x, 0, x);
933 #endif
935 ix = *(ULONGLONG*)&x >> 32;
936 sign = ix >> 31;
937 ix &= 0x7fffffff;
938 if (ix >= 0x44100000) { /* if |x| >= 2^66 */
939 if (isnan(x))
940 return x;
941 z = atanhi[3] + 7.5231638452626401e-37;
942 return sign ? -z : z;
944 if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
945 if (ix < 0x3e400000) { /* |x| < 2^-27 */
946 if (ix < 0x00100000)
947 /* raise underflow for subnormal x */
948 fp_barrierf((float)x);
949 return x;
951 id = -1;
952 } else {
953 x = fabs(x);
954 if (ix < 0x3ff30000) { /* |x| < 1.1875 */
955 if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */
956 id = 0;
957 x = (2.0 * x - 1.0) / (2.0 + x);
958 } else { /* 11/16 <= |x| < 19/16 */
959 id = 1;
960 x = (x - 1.0) / (x + 1.0);
962 } else {
963 if (ix < 0x40038000) { /* |x| < 2.4375 */
964 id = 2;
965 x = (x - 1.5) / (1.0 + 1.5 * x);
966 } else { /* 2.4375 <= |x| < 2^66 */
967 id = 3;
968 x = -1.0 / x;
972 /* end of argument reduction */
973 z = x * x;
974 w = z * z;
975 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
976 s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10])))));
977 s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
978 if (id < 0)
979 return x - x * (s1 + s2);
980 z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x);
981 return sign ? -z : z;
984 /*********************************************************************
985 * MSVCRT_atan2 (MSVCRT.@)
987 * Copied from musl: src/math/atan2.c
989 double CDECL MSVCRT_atan2( double y, double x )
991 static const double pi = 3.1415926535897931160E+00,
992 pi_lo = 1.2246467991473531772E-16;
994 double z;
995 unsigned int m, lx, ly, ix, iy;
997 if (isnan(x) || isnan(y))
998 return x+y;
999 ix = *(ULONGLONG*)&x >> 32;
1000 lx = *(ULONGLONG*)&x;
1001 iy = *(ULONGLONG*)&y >> 32;
1002 ly = *(ULONGLONG*)&y;
1003 if (((ix - 0x3ff00000) | lx) == 0) /* x = 1.0 */
1004 return MSVCRT_atan(y);
1005 m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
1006 ix = ix & 0x7fffffff;
1007 iy = iy & 0x7fffffff;
1009 /* when y = 0 */
1010 if ((iy | ly) == 0) {
1011 switch(m) {
1012 case 0:
1013 case 1: return y; /* atan(+-0,+anything)=+-0 */
1014 case 2: return pi; /* atan(+0,-anything) = pi */
1015 case 3: return -pi; /* atan(-0,-anything) =-pi */
1018 /* when x = 0 */
1019 if ((ix | lx) == 0)
1020 return m & 1 ? -pi / 2 : pi / 2;
1021 /* when x is INF */
1022 if (ix == 0x7ff00000) {
1023 if (iy == 0x7ff00000) {
1024 switch(m) {
1025 case 0: return pi / 4; /* atan(+INF,+INF) */
1026 case 1: return -pi / 4; /* atan(-INF,+INF) */
1027 case 2: return 3 * pi / 4; /* atan(+INF,-INF) */
1028 case 3: return -3 * pi / 4; /* atan(-INF,-INF) */
1030 } else {
1031 switch(m) {
1032 case 0: return 0.0; /* atan(+...,+INF) */
1033 case 1: return -0.0; /* atan(-...,+INF) */
1034 case 2: return pi; /* atan(+...,-INF) */
1035 case 3: return -pi; /* atan(-...,-INF) */
1039 /* |y/x| > 0x1p64 */
1040 if (ix + (64 << 20) < iy || iy == 0x7ff00000)
1041 return m & 1 ? -pi / 2 : pi / 2;
1043 /* z = atan(|y/x|) without spurious underflow */
1044 if ((m & 2) && iy + (64 << 20) < ix) /* |y/x| < 0x1p-64, x<0 */
1045 z = 0;
1046 else
1047 z = MSVCRT_atan(fabs(y / x));
1048 switch (m) {
1049 case 0: return z; /* atan(+,+) */
1050 case 1: return -z; /* atan(-,+) */
1051 case 2: return pi - (z - pi_lo); /* atan(+,-) */
1052 default: /* case 3 */
1053 return (z - pi_lo) - pi; /* atan(-,-) */
1057 /*********************************************************************
1058 * MSVCRT_cos (MSVCRT.@)
1060 double CDECL MSVCRT_cos( double x )
1062 double ret = unix_funcs->cos( x );
1063 if (!isfinite(x)) return math_error(_DOMAIN, "cos", x, 0, ret);
1064 return ret;
1067 /*********************************************************************
1068 * MSVCRT_cosh (MSVCRT.@)
1070 double CDECL MSVCRT_cosh( double x )
1072 double ret = unix_funcs->cosh( x );
1073 if (isnan(x)) return math_error(_DOMAIN, "cosh", x, 0, ret);
1074 return ret;
1077 /*********************************************************************
1078 * MSVCRT_exp (MSVCRT.@)
1080 double CDECL MSVCRT_exp( double x )
1082 double ret = unix_funcs->exp( x );
1083 if (isnan(x)) return math_error(_DOMAIN, "exp", x, 0, ret);
1084 if (isfinite(x) && !ret) return math_error(_UNDERFLOW, "exp", x, 0, ret);
1085 if (isfinite(x) && !isfinite(ret)) return math_error(_OVERFLOW, "exp", x, 0, ret);
1086 return ret;
1089 /*********************************************************************
1090 * MSVCRT_fmod (MSVCRT.@)
1092 double CDECL MSVCRT_fmod( double x, double y )
1094 double ret = unix_funcs->fmod( x, y );
1095 if (!isfinite(x) || !isfinite(y)) return math_error(_DOMAIN, "fmod", x, y, ret);
1096 return ret;
1099 /*********************************************************************
1100 * MSVCRT_log (MSVCRT.@)
1102 double CDECL MSVCRT_log( double x )
1104 double ret = unix_funcs->log( x );
1105 if (x < 0.0) return math_error(_DOMAIN, "log", x, 0, ret);
1106 if (x == 0.0) return math_error(_SING, "log", x, 0, ret);
1107 return ret;
1110 /*********************************************************************
1111 * MSVCRT_log10 (MSVCRT.@)
1113 double CDECL MSVCRT_log10( double x )
1115 double ret = unix_funcs->log10( x );
1116 if (x < 0.0) return math_error(_DOMAIN, "log10", x, 0, ret);
1117 if (x == 0.0) return math_error(_SING, "log10", x, 0, ret);
1118 return ret;
1121 /*********************************************************************
1122 * MSVCRT_pow (MSVCRT.@)
1124 double CDECL MSVCRT_pow( double x, double y )
1126 double z = unix_funcs->pow(x,y);
1127 if (x < 0 && y != MSVCRT_floor(y))
1128 return math_error(_DOMAIN, "pow", x, y, z);
1129 if (!x && isfinite(y) && y < 0)
1130 return math_error(_SING, "pow", x, y, z);
1131 if (isfinite(x) && isfinite(y) && !isfinite(z))
1132 return math_error(_OVERFLOW, "pow", x, y, z);
1133 if (x && isfinite(x) && isfinite(y) && !z)
1134 return math_error(_UNDERFLOW, "pow", x, y, z);
1135 return z;
1138 /*********************************************************************
1139 * MSVCRT_sin (MSVCRT.@)
1141 double CDECL MSVCRT_sin( double x )
1143 double ret = unix_funcs->sin( x );
1144 if (!isfinite(x)) return math_error(_DOMAIN, "sin", x, 0, ret);
1145 return ret;
1148 /*********************************************************************
1149 * MSVCRT_sinh (MSVCRT.@)
1151 double CDECL MSVCRT_sinh( double x )
1153 double ret = unix_funcs->sinh( x );
1154 if (isnan(x)) return math_error(_DOMAIN, "sinh", x, 0, ret);
1155 return ret;
1158 /*********************************************************************
1159 * MSVCRT_sqrt (MSVCRT.@)
1161 * Copied from musl: src/math/sqrt.c
1163 double CDECL MSVCRT_sqrt( double x )
1165 static const double tiny = 1.0e-300;
1167 double z;
1168 int sign = 0x80000000;
1169 int ix0,s0,q,m,t,i;
1170 unsigned int r,t1,s1,ix1,q1;
1171 ULONGLONG ix;
1173 ix = *(ULONGLONG*)&x;
1174 ix0 = ix >> 32;
1175 ix1 = ix;
1177 /* take care of Inf and NaN */
1178 if (isnan(x) || (isinf(x) && x > 0))
1179 return x;
1181 /* take care of zero */
1182 if (ix0 <= 0) {
1183 if (((ix0 & ~sign) | ix1) == 0)
1184 return x; /* sqrt(+-0) = +-0 */
1185 if (ix0 < 0)
1186 return math_error(_DOMAIN, "sqrt", x, 0, (x - x) / (x - x));
1188 /* normalize x */
1189 m = ix0 >> 20;
1190 if (m == 0) { /* subnormal x */
1191 while (ix0 == 0) {
1192 m -= 21;
1193 ix0 |= (ix1 >> 11);
1194 ix1 <<= 21;
1196 for (i=0; (ix0 & 0x00100000) == 0; i++)
1197 ix0 <<= 1;
1198 m -= i - 1;
1199 ix0 |= ix1 >> (32 - i);
1200 ix1 <<= i;
1202 m -= 1023; /* unbias exponent */
1203 ix0 = (ix0 & 0x000fffff) | 0x00100000;
1204 if (m & 1) { /* odd m, double x to make it even */
1205 ix0 += ix0 + ((ix1 & sign) >> 31);
1206 ix1 += ix1;
1208 m >>= 1; /* m = [m/2] */
1210 /* generate sqrt(x) bit by bit */
1211 ix0 += ix0 + ((ix1 & sign) >> 31);
1212 ix1 += ix1;
1213 q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
1214 r = 0x00200000; /* r = moving bit from right to left */
1216 while (r != 0) {
1217 t = s0 + r;
1218 if (t <= ix0) {
1219 s0 = t + r;
1220 ix0 -= t;
1221 q += r;
1223 ix0 += ix0 + ((ix1 & sign) >> 31);
1224 ix1 += ix1;
1225 r >>= 1;
1228 r = sign;
1229 while (r != 0) {
1230 t1 = s1 + r;
1231 t = s0;
1232 if (t < ix0 || (t == ix0 && t1 <= ix1)) {
1233 s1 = t1 + r;
1234 if ((t1&sign) == sign && (s1 & sign) == 0)
1235 s0++;
1236 ix0 -= t;
1237 if (ix1 < t1)
1238 ix0--;
1239 ix1 -= t1;
1240 q1 += r;
1242 ix0 += ix0 + ((ix1 & sign) >> 31);
1243 ix1 += ix1;
1244 r >>= 1;
1247 /* use floating add to find out rounding direction */
1248 if ((ix0 | ix1) != 0) {
1249 z = 1.0 - tiny; /* raise inexact flag */
1250 if (z >= 1.0) {
1251 z = 1.0 + tiny;
1252 if (q1 == (unsigned int)0xffffffff) {
1253 q1 = 0;
1254 q++;
1255 } else if (z > 1.0) {
1256 if (q1 == (unsigned int)0xfffffffe)
1257 q++;
1258 q1 += 2;
1259 } else
1260 q1 += q1 & 1;
1263 ix0 = (q >> 1) + 0x3fe00000;
1264 ix1 = q1 >> 1;
1265 if (q & 1)
1266 ix1 |= sign;
1267 ix = ix0 + ((unsigned int)m << 20);
1268 ix <<= 32;
1269 ix |= ix1;
1270 return *(double*)&ix;
1273 /*********************************************************************
1274 * MSVCRT_tan (MSVCRT.@)
1276 double CDECL MSVCRT_tan( double x )
1278 double ret = unix_funcs->tan(x);
1279 if (!isfinite(x)) return math_error(_DOMAIN, "tan", x, 0, ret);
1280 return ret;
1283 /*********************************************************************
1284 * MSVCRT_tanh (MSVCRT.@)
1286 double CDECL MSVCRT_tanh( double x )
1288 double ret = unix_funcs->tanh(x);
1289 if (isnan(x)) return math_error(_DOMAIN, "tanh", x, 0, ret);
1290 return ret;
1294 #if defined(__GNUC__) && defined(__i386__)
1296 #define CREATE_FPU_FUNC1(name, call) \
1297 __ASM_GLOBAL_FUNC(name, \
1298 "pushl %ebp\n\t" \
1299 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1300 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1301 "movl %esp, %ebp\n\t" \
1302 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1303 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1304 "fstpl (%esp)\n\t" /* store function argument */ \
1305 "fwait\n\t" \
1306 "movl $1, %ecx\n\t" /* empty FPU stack */ \
1307 "1:\n\t" \
1308 "fxam\n\t" \
1309 "fstsw %ax\n\t" \
1310 "and $0x4500, %ax\n\t" \
1311 "cmp $0x4100, %ax\n\t" \
1312 "je 2f\n\t" \
1313 "fstpl (%esp,%ecx,8)\n\t" \
1314 "fwait\n\t" \
1315 "incl %ecx\n\t" \
1316 "jmp 1b\n\t" \
1317 "2:\n\t" \
1318 "movl %ecx, -4(%ebp)\n\t" \
1319 "call " __ASM_NAME( #call ) "\n\t" \
1320 "movl -4(%ebp), %ecx\n\t" \
1321 "fstpl (%esp)\n\t" /* save result */ \
1322 "3:\n\t" /* restore FPU stack */ \
1323 "decl %ecx\n\t" \
1324 "fldl (%esp,%ecx,8)\n\t" \
1325 "cmpl $0, %ecx\n\t" \
1326 "jne 3b\n\t" \
1327 "leave\n\t" \
1328 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1329 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1330 "ret")
1332 #define CREATE_FPU_FUNC2(name, call) \
1333 __ASM_GLOBAL_FUNC(name, \
1334 "pushl %ebp\n\t" \
1335 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1336 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1337 "movl %esp, %ebp\n\t" \
1338 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1339 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1340 "fstpl 8(%esp)\n\t" /* store function argument */ \
1341 "fwait\n\t" \
1342 "fstpl (%esp)\n\t" \
1343 "fwait\n\t" \
1344 "movl $2, %ecx\n\t" /* empty FPU stack */ \
1345 "1:\n\t" \
1346 "fxam\n\t" \
1347 "fstsw %ax\n\t" \
1348 "and $0x4500, %ax\n\t" \
1349 "cmp $0x4100, %ax\n\t" \
1350 "je 2f\n\t" \
1351 "fstpl (%esp,%ecx,8)\n\t" \
1352 "fwait\n\t" \
1353 "incl %ecx\n\t" \
1354 "jmp 1b\n\t" \
1355 "2:\n\t" \
1356 "movl %ecx, -4(%ebp)\n\t" \
1357 "call " __ASM_NAME( #call ) "\n\t" \
1358 "movl -4(%ebp), %ecx\n\t" \
1359 "fstpl 8(%esp)\n\t" /* save result */ \
1360 "3:\n\t" /* restore FPU stack */ \
1361 "decl %ecx\n\t" \
1362 "fldl (%esp,%ecx,8)\n\t" \
1363 "cmpl $1, %ecx\n\t" \
1364 "jne 3b\n\t" \
1365 "leave\n\t" \
1366 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1367 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1368 "ret")
1370 CREATE_FPU_FUNC1(_CIacos, MSVCRT_acos)
1371 CREATE_FPU_FUNC1(_CIasin, MSVCRT_asin)
1372 CREATE_FPU_FUNC1(_CIatan, MSVCRT_atan)
1373 CREATE_FPU_FUNC2(_CIatan2, MSVCRT_atan2)
1374 CREATE_FPU_FUNC1(_CIcos, MSVCRT_cos)
1375 CREATE_FPU_FUNC1(_CIcosh, MSVCRT_cosh)
1376 CREATE_FPU_FUNC1(_CIexp, MSVCRT_exp)
1377 CREATE_FPU_FUNC2(_CIfmod, MSVCRT_fmod)
1378 CREATE_FPU_FUNC1(_CIlog, MSVCRT_log)
1379 CREATE_FPU_FUNC1(_CIlog10, MSVCRT_log10)
1380 CREATE_FPU_FUNC2(_CIpow, MSVCRT_pow)
1381 CREATE_FPU_FUNC1(_CIsin, MSVCRT_sin)
1382 CREATE_FPU_FUNC1(_CIsinh, MSVCRT_sinh)
1383 CREATE_FPU_FUNC1(_CIsqrt, MSVCRT_sqrt)
1384 CREATE_FPU_FUNC1(_CItan, MSVCRT_tan)
1385 CREATE_FPU_FUNC1(_CItanh, MSVCRT_tanh)
1387 __ASM_GLOBAL_FUNC(MSVCRT__ftol,
1388 "pushl %ebp\n\t"
1389 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1390 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1391 "movl %esp, %ebp\n\t"
1392 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1393 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
1394 "fnstcw (%esp)\n\t"
1395 "mov (%esp), %ax\n\t"
1396 "or $0xc00, %ax\n\t"
1397 "mov %ax, 2(%esp)\n\t"
1398 "fldcw 2(%esp)\n\t"
1399 "fistpq 4(%esp)\n\t"
1400 "fldcw (%esp)\n\t"
1401 "movl 4(%esp), %eax\n\t"
1402 "movl 8(%esp), %edx\n\t"
1403 "leave\n\t"
1404 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1405 __ASM_CFI(".cfi_same_value %ebp\n\t")
1406 "ret")
1408 #endif /* defined(__GNUC__) && defined(__i386__) */
1410 /*********************************************************************
1411 * _fpclass (MSVCRT.@)
1413 int CDECL MSVCRT__fpclass(double num)
1415 union { double f; UINT64 i; } u = { num };
1416 int e = u.i >> 52 & 0x7ff;
1417 int s = u.i >> 63;
1419 switch (e)
1421 case 0:
1422 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
1423 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
1424 case 0x7ff:
1425 if (u.i << 12) return ((u.i >> 51) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
1426 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
1427 default:
1428 return s ? _FPCLASS_NN : _FPCLASS_PN;
1432 /*********************************************************************
1433 * _rotl (MSVCRT.@)
1435 unsigned int CDECL _rotl(unsigned int num, int shift)
1437 shift &= 31;
1438 return (num << shift) | (num >> (32-shift));
1441 /*********************************************************************
1442 * _lrotl (MSVCRT.@)
1444 __msvcrt_ulong CDECL MSVCRT__lrotl(__msvcrt_ulong num, int shift)
1446 shift &= 0x1f;
1447 return (num << shift) | (num >> (32-shift));
1450 /*********************************************************************
1451 * _lrotr (MSVCRT.@)
1453 __msvcrt_ulong CDECL MSVCRT__lrotr(__msvcrt_ulong num, int shift)
1455 shift &= 0x1f;
1456 return (num >> shift) | (num << (32-shift));
1459 /*********************************************************************
1460 * _rotr (MSVCRT.@)
1462 unsigned int CDECL _rotr(unsigned int num, int shift)
1464 shift &= 0x1f;
1465 return (num >> shift) | (num << (32-shift));
1468 /*********************************************************************
1469 * _rotl64 (MSVCRT.@)
1471 unsigned __int64 CDECL _rotl64(unsigned __int64 num, int shift)
1473 shift &= 63;
1474 return (num << shift) | (num >> (64-shift));
1477 /*********************************************************************
1478 * _rotr64 (MSVCRT.@)
1480 unsigned __int64 CDECL _rotr64(unsigned __int64 num, int shift)
1482 shift &= 63;
1483 return (num >> shift) | (num << (64-shift));
1486 /*********************************************************************
1487 * abs (MSVCRT.@)
1489 int CDECL MSVCRT_abs( int n )
1491 return n >= 0 ? n : -n;
1494 /*********************************************************************
1495 * labs (MSVCRT.@)
1497 __msvcrt_long CDECL MSVCRT_labs( __msvcrt_long n )
1499 return n >= 0 ? n : -n;
1502 #if _MSVCR_VER>=100
1503 /*********************************************************************
1504 * llabs (MSVCR100.@)
1506 __int64 CDECL MSVCRT_llabs( __int64 n )
1508 return n >= 0 ? n : -n;
1510 #endif
1512 #if _MSVCR_VER>=120
1513 /*********************************************************************
1514 * imaxabs (MSVCR120.@)
1516 intmax_t CDECL MSVCRT_imaxabs( intmax_t n )
1518 return n >= 0 ? n : -n;
1520 #endif
1522 /*********************************************************************
1523 * _abs64 (MSVCRT.@)
1525 __int64 CDECL _abs64( __int64 n )
1527 return n >= 0 ? n : -n;
1530 /*********************************************************************
1531 * _logb (MSVCRT.@)
1533 double CDECL MSVCRT__logb(double num)
1535 double ret = unix_funcs->logb(num);
1536 if (isnan(num)) return math_error(_DOMAIN, "_logb", num, 0, ret);
1537 if (!num) return math_error(_SING, "_logb", num, 0, ret);
1538 return ret;
1541 /*********************************************************************
1542 * _hypot (MSVCRT.@)
1544 double CDECL _hypot(double x, double y)
1546 /* FIXME: errno handling */
1547 return unix_funcs->hypot( x, y );
1550 /*********************************************************************
1551 * _hypotf (MSVCRT.@)
1553 float CDECL MSVCRT__hypotf(float x, float y)
1555 /* FIXME: errno handling */
1556 return unix_funcs->hypotf( x, y );
1559 /*********************************************************************
1560 * ceil (MSVCRT.@)
1562 double CDECL MSVCRT_ceil( double x )
1564 return unix_funcs->ceil(x);
1567 /*********************************************************************
1568 * floor (MSVCRT.@)
1570 double CDECL MSVCRT_floor( double x )
1572 return unix_funcs->floor(x);
1575 /*********************************************************************
1576 * fma (MSVCRT.@)
1578 double CDECL MSVCRT_fma( double x, double y, double z )
1580 double w = unix_funcs->fma(x, y, z);
1581 if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *_errno() = EDOM;
1582 else if (isinf(x) && isinf(z) && x != z) *_errno() = EDOM;
1583 else if (isinf(y) && isinf(z) && y != z) *_errno() = EDOM;
1584 return w;
1587 /*********************************************************************
1588 * fmaf (MSVCRT.@)
1590 float CDECL MSVCRT_fmaf( float x, float y, float z )
1592 float w = unix_funcs->fmaf(x, y, z);
1593 if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *_errno() = EDOM;
1594 else if (isinf(x) && isinf(z) && x != z) *_errno() = EDOM;
1595 else if (isinf(y) && isinf(z) && y != z) *_errno() = EDOM;
1596 return w;
1599 /*********************************************************************
1600 * fabs (MSVCRT.@)
1602 * Copied from musl: src/math/fabsf.c
1604 double CDECL MSVCRT_fabs( double x )
1606 union { double f; UINT64 i; } u = { x };
1607 u.i &= ~0ull >> 1;
1608 return u.f;
1611 /*********************************************************************
1612 * frexp (MSVCRT.@)
1614 double CDECL MSVCRT_frexp( double x, int *exp )
1616 return unix_funcs->frexp( x, exp );
1619 /*********************************************************************
1620 * modf (MSVCRT.@)
1622 double CDECL MSVCRT_modf( double x, double *iptr )
1624 return unix_funcs->modf( x, iptr );
1627 /**********************************************************************
1628 * _statusfp2 (MSVCRT.@)
1630 * Not exported by native msvcrt, added in msvcr80.
1632 #if defined(__i386__) || defined(__x86_64__)
1633 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
1635 #ifdef __GNUC__
1636 unsigned int flags;
1637 unsigned long fpword;
1639 if (x86_sw)
1641 __asm__ __volatile__( "fstsw %0" : "=m" (fpword) );
1642 flags = 0;
1643 if (fpword & 0x1) flags |= _SW_INVALID;
1644 if (fpword & 0x2) flags |= _SW_DENORMAL;
1645 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1646 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1647 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1648 if (fpword & 0x20) flags |= _SW_INEXACT;
1649 *x86_sw = flags;
1652 if (!sse2_sw) return;
1654 if (sse2_supported)
1656 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1657 flags = 0;
1658 if (fpword & 0x1) flags |= _SW_INVALID;
1659 if (fpword & 0x2) flags |= _SW_DENORMAL;
1660 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1661 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1662 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1663 if (fpword & 0x20) flags |= _SW_INEXACT;
1664 *sse2_sw = flags;
1666 else *sse2_sw = 0;
1667 #else
1668 FIXME( "not implemented\n" );
1669 #endif
1671 #endif
1673 /**********************************************************************
1674 * _statusfp (MSVCRT.@)
1676 unsigned int CDECL _statusfp(void)
1678 unsigned int flags = 0;
1679 #if defined(__i386__) || defined(__x86_64__)
1680 unsigned int x86_sw, sse2_sw;
1682 _statusfp2( &x86_sw, &sse2_sw );
1683 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1684 flags = x86_sw | sse2_sw;
1685 #elif defined(__aarch64__)
1686 ULONG_PTR fpsr;
1688 __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
1689 if (fpsr & 0x1) flags |= _SW_INVALID;
1690 if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
1691 if (fpsr & 0x4) flags |= _SW_OVERFLOW;
1692 if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
1693 if (fpsr & 0x10) flags |= _SW_INEXACT;
1694 if (fpsr & 0x80) flags |= _SW_DENORMAL;
1695 #else
1696 FIXME( "not implemented\n" );
1697 #endif
1698 return flags;
1701 /*********************************************************************
1702 * _clearfp (MSVCRT.@)
1704 unsigned int CDECL _clearfp(void)
1706 unsigned int flags = 0;
1707 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1708 unsigned long fpword;
1710 __asm__ __volatile__( "fnstsw %0; fnclex" : "=m" (fpword) );
1711 if (fpword & 0x1) flags |= _SW_INVALID;
1712 if (fpword & 0x2) flags |= _SW_DENORMAL;
1713 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1714 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1715 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1716 if (fpword & 0x20) flags |= _SW_INEXACT;
1718 if (sse2_supported)
1720 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1721 if (fpword & 0x1) flags |= _SW_INVALID;
1722 if (fpword & 0x2) flags |= _SW_DENORMAL;
1723 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1724 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1725 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1726 if (fpword & 0x20) flags |= _SW_INEXACT;
1727 fpword &= ~0x3f;
1728 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1730 #elif defined(__aarch64__)
1731 ULONG_PTR fpsr;
1733 __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
1734 if (fpsr & 0x1) flags |= _SW_INVALID;
1735 if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
1736 if (fpsr & 0x4) flags |= _SW_OVERFLOW;
1737 if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
1738 if (fpsr & 0x10) flags |= _SW_INEXACT;
1739 if (fpsr & 0x80) flags |= _SW_DENORMAL;
1740 fpsr &= ~0x9f;
1741 __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) );
1742 #else
1743 FIXME( "not implemented\n" );
1744 #endif
1745 return flags;
1748 /*********************************************************************
1749 * __fpecode (MSVCRT.@)
1751 int * CDECL __fpecode(void)
1753 return &msvcrt_get_thread_data()->fpecode;
1756 /*********************************************************************
1757 * ldexp (MSVCRT.@)
1759 double CDECL MSVCRT_ldexp(double num, __msvcrt_long exp)
1761 double z = unix_funcs->ldexp(num,exp);
1763 if (isfinite(num) && !isfinite(z))
1764 return math_error(_OVERFLOW, "ldexp", num, exp, z);
1765 if (num && isfinite(num) && !z)
1766 return math_error(_UNDERFLOW, "ldexp", num, exp, z);
1767 if (z == 0 && signbit(z))
1768 z = 0.0; /* Convert -0 -> +0 */
1769 return z;
1772 /*********************************************************************
1773 * _cabs (MSVCRT.@)
1775 double CDECL MSVCRT__cabs(struct _complex num)
1777 return MSVCRT_sqrt(num.x * num.x + num.y * num.y);
1780 /*********************************************************************
1781 * _chgsign (MSVCRT.@)
1783 double CDECL MSVCRT__chgsign(double num)
1785 union { double f; UINT64 i; } u = { num };
1786 u.i ^= 1ull << 63;
1787 return u.f;
1790 /*********************************************************************
1791 * __control87_2 (MSVCR80.@)
1793 * Not exported by native msvcrt, added in msvcr80.
1795 #ifdef __i386__
1796 int CDECL __control87_2( unsigned int newval, unsigned int mask,
1797 unsigned int *x86_cw, unsigned int *sse2_cw )
1799 #ifdef __GNUC__
1800 unsigned long fpword;
1801 unsigned int flags;
1802 unsigned int old_flags;
1804 if (x86_cw)
1806 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
1808 /* Convert into mask constants */
1809 flags = 0;
1810 if (fpword & 0x1) flags |= MSVCRT__EM_INVALID;
1811 if (fpword & 0x2) flags |= MSVCRT__EM_DENORMAL;
1812 if (fpword & 0x4) flags |= MSVCRT__EM_ZERODIVIDE;
1813 if (fpword & 0x8) flags |= MSVCRT__EM_OVERFLOW;
1814 if (fpword & 0x10) flags |= MSVCRT__EM_UNDERFLOW;
1815 if (fpword & 0x20) flags |= MSVCRT__EM_INEXACT;
1816 switch (fpword & 0xc00)
1818 case 0xc00: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
1819 case 0x800: flags |= MSVCRT__RC_UP; break;
1820 case 0x400: flags |= MSVCRT__RC_DOWN; break;
1822 switch (fpword & 0x300)
1824 case 0x0: flags |= MSVCRT__PC_24; break;
1825 case 0x200: flags |= MSVCRT__PC_53; break;
1826 case 0x300: flags |= MSVCRT__PC_64; break;
1828 if (fpword & 0x1000) flags |= MSVCRT__IC_AFFINE;
1830 TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1831 if (mask)
1833 flags = (flags & ~mask) | (newval & mask);
1835 /* Convert (masked) value back to fp word */
1836 fpword = 0;
1837 if (flags & MSVCRT__EM_INVALID) fpword |= 0x1;
1838 if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x2;
1839 if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x4;
1840 if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x8;
1841 if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x10;
1842 if (flags & MSVCRT__EM_INEXACT) fpword |= 0x20;
1843 switch (flags & MSVCRT__MCW_RC)
1845 case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0xc00; break;
1846 case MSVCRT__RC_UP: fpword |= 0x800; break;
1847 case MSVCRT__RC_DOWN: fpword |= 0x400; break;
1849 switch (flags & MSVCRT__MCW_PC)
1851 case MSVCRT__PC_64: fpword |= 0x300; break;
1852 case MSVCRT__PC_53: fpword |= 0x200; break;
1853 case MSVCRT__PC_24: fpword |= 0x0; break;
1855 if (flags & MSVCRT__IC_AFFINE) fpword |= 0x1000;
1857 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1859 *x86_cw = flags;
1862 if (!sse2_cw) return 1;
1864 if (sse2_supported)
1866 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1868 /* Convert into mask constants */
1869 flags = 0;
1870 if (fpword & 0x80) flags |= MSVCRT__EM_INVALID;
1871 if (fpword & 0x100) flags |= MSVCRT__EM_DENORMAL;
1872 if (fpword & 0x200) flags |= MSVCRT__EM_ZERODIVIDE;
1873 if (fpword & 0x400) flags |= MSVCRT__EM_OVERFLOW;
1874 if (fpword & 0x800) flags |= MSVCRT__EM_UNDERFLOW;
1875 if (fpword & 0x1000) flags |= MSVCRT__EM_INEXACT;
1876 switch (fpword & 0x6000)
1878 case 0x6000: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
1879 case 0x4000: flags |= MSVCRT__RC_UP; break;
1880 case 0x2000: flags |= MSVCRT__RC_DOWN; break;
1882 switch (fpword & 0x8040)
1884 case 0x0040: flags |= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1885 case 0x8000: flags |= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1886 case 0x8040: flags |= MSVCRT__DN_FLUSH; break;
1889 TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1890 if (mask)
1892 old_flags = flags;
1893 mask &= MSVCRT__MCW_EM | MSVCRT__MCW_RC | MSVCRT__MCW_DN;
1894 flags = (flags & ~mask) | (newval & mask);
1896 if (flags != old_flags)
1898 /* Convert (masked) value back to fp word */
1899 fpword = 0;
1900 if (flags & MSVCRT__EM_INVALID) fpword |= 0x80;
1901 if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x100;
1902 if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
1903 if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
1904 if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
1905 if (flags & MSVCRT__EM_INEXACT) fpword |= 0x1000;
1906 switch (flags & MSVCRT__MCW_RC)
1908 case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0x6000; break;
1909 case MSVCRT__RC_UP: fpword |= 0x4000; break;
1910 case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
1912 switch (flags & MSVCRT__MCW_DN)
1914 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1915 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1916 case MSVCRT__DN_FLUSH: fpword |= 0x8040; break;
1918 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1921 *sse2_cw = flags;
1923 else *sse2_cw = 0;
1925 return 1;
1926 #else
1927 FIXME( "not implemented\n" );
1928 return 0;
1929 #endif
1931 #endif
1933 /*********************************************************************
1934 * _control87 (MSVCRT.@)
1936 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1938 unsigned int flags = 0;
1939 #ifdef __i386__
1940 unsigned int sse2_cw;
1942 __control87_2( newval, mask, &flags, &sse2_cw );
1944 if ((flags ^ sse2_cw) & (MSVCRT__MCW_EM | MSVCRT__MCW_RC)) flags |= MSVCRT__EM_AMBIGUOUS;
1945 flags |= sse2_cw;
1946 #elif defined(__x86_64__)
1947 unsigned long fpword;
1948 unsigned int old_flags;
1950 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1951 if (fpword & 0x80) flags |= MSVCRT__EM_INVALID;
1952 if (fpword & 0x100) flags |= MSVCRT__EM_DENORMAL;
1953 if (fpword & 0x200) flags |= MSVCRT__EM_ZERODIVIDE;
1954 if (fpword & 0x400) flags |= MSVCRT__EM_OVERFLOW;
1955 if (fpword & 0x800) flags |= MSVCRT__EM_UNDERFLOW;
1956 if (fpword & 0x1000) flags |= MSVCRT__EM_INEXACT;
1957 switch (fpword & 0x6000)
1959 case 0x6000: flags |= MSVCRT__RC_CHOP; break;
1960 case 0x4000: flags |= MSVCRT__RC_UP; break;
1961 case 0x2000: flags |= MSVCRT__RC_DOWN; break;
1963 switch (fpword & 0x8040)
1965 case 0x0040: flags |= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1966 case 0x8000: flags |= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1967 case 0x8040: flags |= MSVCRT__DN_FLUSH; break;
1969 old_flags = flags;
1970 mask &= MSVCRT__MCW_EM | MSVCRT__MCW_RC | MSVCRT__MCW_DN;
1971 flags = (flags & ~mask) | (newval & mask);
1972 if (flags != old_flags)
1974 fpword = 0;
1975 if (flags & MSVCRT__EM_INVALID) fpword |= 0x80;
1976 if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x100;
1977 if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
1978 if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
1979 if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
1980 if (flags & MSVCRT__EM_INEXACT) fpword |= 0x1000;
1981 switch (flags & MSVCRT__MCW_RC)
1983 case MSVCRT__RC_CHOP: fpword |= 0x6000; break;
1984 case MSVCRT__RC_UP: fpword |= 0x4000; break;
1985 case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
1987 switch (flags & MSVCRT__MCW_DN)
1989 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1990 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1991 case MSVCRT__DN_FLUSH: fpword |= 0x8040; break;
1993 __asm__ __volatile__( "ldmxcsr %0" :: "m" (fpword) );
1995 #elif defined(__aarch64__)
1996 ULONG_PTR fpcr;
1998 __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) );
1999 if (!(fpcr & 0x100)) flags |= MSVCRT__EM_INVALID;
2000 if (!(fpcr & 0x200)) flags |= MSVCRT__EM_ZERODIVIDE;
2001 if (!(fpcr & 0x400)) flags |= MSVCRT__EM_OVERFLOW;
2002 if (!(fpcr & 0x800)) flags |= MSVCRT__EM_UNDERFLOW;
2003 if (!(fpcr & 0x1000)) flags |= MSVCRT__EM_INEXACT;
2004 if (!(fpcr & 0x8000)) flags |= MSVCRT__EM_DENORMAL;
2005 switch (fpcr & 0xc00000)
2007 case 0x400000: flags |= MSVCRT__RC_UP; break;
2008 case 0x800000: flags |= MSVCRT__RC_DOWN; break;
2009 case 0xc00000: flags |= MSVCRT__RC_CHOP; break;
2011 flags = (flags & ~mask) | (newval & mask);
2012 fpcr &= ~0xc09f00ul;
2013 if (!(flags & MSVCRT__EM_INVALID)) fpcr |= 0x100;
2014 if (!(flags & MSVCRT__EM_ZERODIVIDE)) fpcr |= 0x200;
2015 if (!(flags & MSVCRT__EM_OVERFLOW)) fpcr |= 0x400;
2016 if (!(flags & MSVCRT__EM_UNDERFLOW)) fpcr |= 0x800;
2017 if (!(flags & MSVCRT__EM_INEXACT)) fpcr |= 0x1000;
2018 if (!(flags & MSVCRT__EM_DENORMAL)) fpcr |= 0x8000;
2019 switch (flags & MSVCRT__MCW_RC)
2021 case MSVCRT__RC_CHOP: fpcr |= 0xc00000; break;
2022 case MSVCRT__RC_UP: fpcr |= 0x400000; break;
2023 case MSVCRT__RC_DOWN: fpcr |= 0x800000; break;
2025 __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) );
2026 #else
2027 FIXME( "not implemented\n" );
2028 #endif
2029 return flags;
2032 /*********************************************************************
2033 * _controlfp (MSVCRT.@)
2035 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
2037 return _control87( newval, mask & ~MSVCRT__EM_DENORMAL );
2040 /*********************************************************************
2041 * _set_controlfp (MSVCRT.@)
2043 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
2045 _controlfp( newval, mask );
2048 /*********************************************************************
2049 * _controlfp_s (MSVCRT.@)
2051 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
2053 static const unsigned int all_flags = (MSVCRT__MCW_EM | MSVCRT__MCW_IC | MSVCRT__MCW_RC |
2054 MSVCRT__MCW_PC | MSVCRT__MCW_DN);
2055 unsigned int val;
2057 if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
2059 if (cur) *cur = _controlfp( 0, 0 ); /* retrieve it anyway */
2060 return EINVAL;
2062 val = _controlfp( newval, mask );
2063 if (cur) *cur = val;
2064 return 0;
2067 #if _MSVCR_VER>=120
2068 /*********************************************************************
2069 * fegetenv (MSVCR120.@)
2071 int CDECL MSVCRT_fegetenv(fenv_t *env)
2073 env->_Fe_ctl = _controlfp(0, 0) & (MSVCRT__EM_INEXACT | MSVCRT__EM_UNDERFLOW |
2074 MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID | MSVCRT__RC_CHOP);
2075 env->_Fe_stat = _statusfp();
2076 return 0;
2078 #endif
2080 #if _MSVCR_VER>=140
2081 /*********************************************************************
2082 * __fpe_flt_rounds (UCRTBASE.@)
2084 int CDECL __fpe_flt_rounds(void)
2086 unsigned int fpc = _controlfp(0, 0) & MSVCRT__RC_CHOP;
2088 TRACE("()\n");
2090 switch(fpc) {
2091 case MSVCRT__RC_CHOP: return 0;
2092 case MSVCRT__RC_NEAR: return 1;
2093 case MSVCRT__RC_UP: return 2;
2094 default: return 3;
2097 #endif
2099 #if _MSVCR_VER>=120
2101 /*********************************************************************
2102 * fegetround (MSVCR120.@)
2104 int CDECL MSVCRT_fegetround(void)
2106 return _controlfp(0, 0) & MSVCRT__RC_CHOP;
2109 /*********************************************************************
2110 * fesetround (MSVCR120.@)
2112 int CDECL MSVCRT_fesetround(int round_mode)
2114 if (round_mode & (~MSVCRT__RC_CHOP))
2115 return 1;
2116 _controlfp(round_mode, MSVCRT__RC_CHOP);
2117 return 0;
2120 #endif /* _MSVCR_VER>=120 */
2122 /*********************************************************************
2123 * _copysign (MSVCRT.@)
2125 * Copied from musl: src/math/copysign.c
2127 double CDECL MSVCRT__copysign( double x, double y )
2129 union { double f; UINT64 i; } ux = { x }, uy = { y };
2130 ux.i &= ~0ull >> 1;
2131 ux.i |= uy.i & 1ull << 63;
2132 return ux.f;
2135 /*********************************************************************
2136 * _finite (MSVCRT.@)
2138 int CDECL MSVCRT__finite(double num)
2140 union { double f; UINT64 i; } u = { num };
2141 return (u.i & ~0ull >> 1) < 0x7ffull << 52;
2144 /*********************************************************************
2145 * _fpreset (MSVCRT.@)
2147 void CDECL _fpreset(void)
2149 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2150 const unsigned int x86_cw = 0x27f;
2151 __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
2152 if (sse2_supported)
2154 const unsigned long sse2_cw = 0x1f80;
2155 __asm__ __volatile__( "ldmxcsr %0" : : "m" (sse2_cw) );
2157 #else
2158 FIXME( "not implemented\n" );
2159 #endif
2162 #if _MSVCR_VER>=120
2163 /*********************************************************************
2164 * fesetenv (MSVCR120.@)
2166 int CDECL MSVCRT_fesetenv(const fenv_t *env)
2168 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2169 struct {
2170 WORD control_word;
2171 WORD unused1;
2172 WORD status_word;
2173 WORD unused2;
2174 WORD tag_word;
2175 WORD unused3;
2176 DWORD instruction_pointer;
2177 WORD code_segment;
2178 WORD unused4;
2179 DWORD operand_addr;
2180 WORD data_segment;
2181 WORD unused5;
2182 } fenv;
2184 TRACE( "(%p)\n", env );
2186 if (!env->_Fe_ctl && !env->_Fe_stat) {
2187 _fpreset();
2188 return 0;
2191 __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
2193 fenv.control_word &= ~0xc3d;
2194 if (env->_Fe_ctl & MSVCRT__EM_INVALID) fenv.control_word |= 0x1;
2195 if (env->_Fe_ctl & MSVCRT__EM_ZERODIVIDE) fenv.control_word |= 0x4;
2196 if (env->_Fe_ctl & MSVCRT__EM_OVERFLOW) fenv.control_word |= 0x8;
2197 if (env->_Fe_ctl & MSVCRT__EM_UNDERFLOW) fenv.control_word |= 0x10;
2198 if (env->_Fe_ctl & MSVCRT__EM_INEXACT) fenv.control_word |= 0x20;
2199 switch (env->_Fe_ctl & MSVCRT__MCW_RC)
2201 case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fenv.control_word |= 0xc00; break;
2202 case MSVCRT__RC_UP: fenv.control_word |= 0x800; break;
2203 case MSVCRT__RC_DOWN: fenv.control_word |= 0x400; break;
2206 fenv.status_word &= ~0x3d;
2207 if (env->_Fe_stat & FE_INVALID) fenv.status_word |= 0x1;
2208 if (env->_Fe_stat & FE_DIVBYZERO) fenv.status_word |= 0x4;
2209 if (env->_Fe_stat & FE_OVERFLOW) fenv.status_word |= 0x8;
2210 if (env->_Fe_stat & FE_UNDERFLOW) fenv.status_word |= 0x10;
2211 if (env->_Fe_stat & FE_INEXACT) fenv.status_word |= 0x20;
2213 __asm__ __volatile__( "fldenv %0" : : "m" (fenv) : "st", "st(1)",
2214 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
2216 if (sse2_supported)
2218 DWORD fpword;
2219 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
2220 fpword &= ~0x7e80;
2221 if (env->_Fe_ctl & MSVCRT__EM_INVALID) fpword |= 0x80;
2222 if (env->_Fe_ctl & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
2223 if (env->_Fe_ctl & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
2224 if (env->_Fe_ctl & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
2225 if (env->_Fe_ctl & MSVCRT__EM_INEXACT) fpword |= 0x1000;
2226 switch (env->_Fe_ctl & MSVCRT__MCW_RC)
2228 case MSVCRT__RC_CHOP: fpword |= 0x6000; break;
2229 case MSVCRT__RC_UP: fpword |= 0x4000; break;
2230 case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
2232 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
2235 return 0;
2236 #else
2237 FIXME( "not implemented\n" );
2238 #endif
2239 return 1;
2241 #endif
2243 /*********************************************************************
2244 * _isnan (MSVCRT.@)
2246 int CDECL MSVCRT__isnan(double num)
2248 union { double f; UINT64 i; } u = { num };
2249 return (u.i & ~0ull >> 1) > 0x7ffull << 52;
2252 /*********************************************************************
2253 * _j0 (MSVCRT.@)
2255 double CDECL MSVCRT__j0(double num)
2257 /* FIXME: errno handling */
2258 return unix_funcs->j0( num );
2261 /*********************************************************************
2262 * _j1 (MSVCRT.@)
2264 double CDECL MSVCRT__j1(double num)
2266 /* FIXME: errno handling */
2267 return unix_funcs->j1( num );
2270 /*********************************************************************
2271 * _jn (MSVCRT.@)
2273 double CDECL MSVCRT__jn(int n, double num)
2275 /* FIXME: errno handling */
2276 return unix_funcs->jn( n, num );
2279 /*********************************************************************
2280 * _y0 (MSVCRT.@)
2282 double CDECL MSVCRT__y0(double num)
2284 double retval;
2286 if (!isfinite(num)) *_errno() = EDOM;
2287 retval = unix_funcs->y0( num );
2288 if (MSVCRT__fpclass(retval) == _FPCLASS_NINF)
2290 *_errno() = EDOM;
2291 retval = NAN;
2293 return retval;
2296 /*********************************************************************
2297 * _y1 (MSVCRT.@)
2299 double CDECL MSVCRT__y1(double num)
2301 double retval;
2303 if (!isfinite(num)) *_errno() = EDOM;
2304 retval = unix_funcs->y1( num );
2305 if (MSVCRT__fpclass(retval) == _FPCLASS_NINF)
2307 *_errno() = EDOM;
2308 retval = NAN;
2310 return retval;
2313 /*********************************************************************
2314 * _yn (MSVCRT.@)
2316 double CDECL MSVCRT__yn(int order, double num)
2318 double retval;
2320 if (!isfinite(num)) *_errno() = EDOM;
2321 retval = unix_funcs->yn( order, num );
2322 if (MSVCRT__fpclass(retval) == _FPCLASS_NINF)
2324 *_errno() = EDOM;
2325 retval = NAN;
2327 return retval;
2330 #if _MSVCR_VER>=120
2332 /*********************************************************************
2333 * _nearbyint (MSVCR120.@)
2335 double CDECL MSVCRT_nearbyint(double num)
2337 return unix_funcs->nearbyint( num );
2340 /*********************************************************************
2341 * _nearbyintf (MSVCR120.@)
2343 float CDECL MSVCRT_nearbyintf(float num)
2345 return unix_funcs->nearbyintf( num );
2348 /*********************************************************************
2349 * nexttoward (MSVCR120.@)
2351 double CDECL MSVCRT_nexttoward(double num, double next)
2353 double ret = unix_funcs->nexttoward(num, next);
2354 if (!(MSVCRT__fpclass(ret) & (_FPCLASS_PN | _FPCLASS_NN
2355 | _FPCLASS_SNAN | _FPCLASS_QNAN)) && !isinf(num))
2357 *_errno() = ERANGE;
2359 return ret;
2362 /*********************************************************************
2363 * nexttowardf (MSVCR120.@)
2365 float CDECL MSVCRT_nexttowardf(float num, double next)
2367 float ret = unix_funcs->nexttowardf( num, next );
2368 if (!(MSVCRT__fpclass(ret) & (_FPCLASS_PN | _FPCLASS_NN
2369 | _FPCLASS_SNAN | _FPCLASS_QNAN)) && !isinf(num))
2371 *_errno() = ERANGE;
2373 return ret;
2376 #endif /* _MSVCR_VER>=120 */
2378 /*********************************************************************
2379 * _nextafter (MSVCRT.@)
2381 double CDECL MSVCRT__nextafter(double num, double next)
2383 double retval;
2384 if (!isfinite(num) || !isfinite(next)) *_errno() = EDOM;
2385 retval = unix_funcs->nextafter(num,next);
2386 return retval;
2389 /*********************************************************************
2390 * _ecvt (MSVCRT.@)
2392 char * CDECL MSVCRT__ecvt( double number, int ndigits, int *decpt, int *sign )
2394 int prec, len;
2395 thread_data_t *data = msvcrt_get_thread_data();
2396 /* FIXME: check better for overflow (native supports over 300 chars) */
2397 ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
2398 * 4 for exponent and one for
2399 * terminating '\0' */
2400 if (!data->efcvt_buffer)
2401 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
2403 if( number < 0) {
2404 *sign = TRUE;
2405 number = -number;
2406 } else
2407 *sign = FALSE;
2408 /* handle cases with zero ndigits or less */
2409 prec = ndigits;
2410 if( prec < 1) prec = 2;
2411 len = MSVCRT__snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
2412 /* take the decimal "point away */
2413 if( prec != 1)
2414 memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
2415 /* take the exponential "e" out */
2416 data->efcvt_buffer[ prec] = '\0';
2417 /* read the exponent */
2418 MSVCRT_sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
2419 (*decpt)++;
2420 /* adjust for some border cases */
2421 if( data->efcvt_buffer[0] == '0')/* value is zero */
2422 *decpt = 0;
2423 /* handle cases with zero ndigits or less */
2424 if( ndigits < 1){
2425 if( data->efcvt_buffer[ 0] >= '5')
2426 (*decpt)++;
2427 data->efcvt_buffer[ 0] = '\0';
2429 TRACE("out=\"%s\"\n",data->efcvt_buffer);
2430 return data->efcvt_buffer;
2433 /*********************************************************************
2434 * _ecvt_s (MSVCRT.@)
2436 int CDECL MSVCRT__ecvt_s( char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign )
2438 int prec, len;
2439 char *result;
2440 const char infret[] = "1#INF";
2442 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
2443 if (!MSVCRT_CHECK_PMT(decpt != NULL)) return EINVAL;
2444 if (!MSVCRT_CHECK_PMT(sign != NULL)) return EINVAL;
2445 if (!MSVCRT_CHECK_PMT_ERR( length > 2, ERANGE )) return ERANGE;
2446 if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, ERANGE )) return ERANGE;
2448 /* special case - inf */
2449 if(number == HUGE_VAL || number == -HUGE_VAL)
2451 memset(buffer, '0', ndigits);
2452 memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
2453 buffer[ndigits] = '\0';
2454 (*decpt) = 1;
2455 if(number == -HUGE_VAL)
2456 (*sign) = 1;
2457 else
2458 (*sign) = 0;
2459 return 0;
2461 /* handle cases with zero ndigits or less */
2462 prec = ndigits;
2463 if( prec < 1) prec = 2;
2464 result = malloc(prec + 7);
2466 if( number < 0) {
2467 *sign = TRUE;
2468 number = -number;
2469 } else
2470 *sign = FALSE;
2471 len = MSVCRT__snprintf(result, prec + 7, "%.*le", prec - 1, number);
2472 /* take the decimal "point away */
2473 if( prec != 1)
2474 memmove( result + 1, result + 2, len - 1 );
2475 /* take the exponential "e" out */
2476 result[ prec] = '\0';
2477 /* read the exponent */
2478 MSVCRT_sscanf( result + prec + 1, "%d", decpt);
2479 (*decpt)++;
2480 /* adjust for some border cases */
2481 if( result[0] == '0')/* value is zero */
2482 *decpt = 0;
2483 /* handle cases with zero ndigits or less */
2484 if( ndigits < 1){
2485 if( result[ 0] >= '5')
2486 (*decpt)++;
2487 result[ 0] = '\0';
2489 memcpy( buffer, result, max(ndigits + 1, 1) );
2490 free( result );
2491 return 0;
2494 /***********************************************************************
2495 * _fcvt (MSVCRT.@)
2497 char * CDECL MSVCRT__fcvt( double number, int ndigits, int *decpt, int *sign )
2499 thread_data_t *data = msvcrt_get_thread_data();
2500 int stop, dec1, dec2;
2501 char *ptr1, *ptr2, *first;
2502 char buf[80]; /* ought to be enough */
2503 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
2505 if (!data->efcvt_buffer)
2506 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
2508 if (number < 0)
2510 *sign = 1;
2511 number = -number;
2512 } else *sign = 0;
2514 stop = MSVCRT__snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
2515 ptr1 = buf;
2516 ptr2 = data->efcvt_buffer;
2517 first = NULL;
2518 dec1 = 0;
2519 dec2 = 0;
2521 /* For numbers below the requested resolution, work out where
2522 the decimal point will be rather than finding it in the string */
2523 if (number < 1.0 && number > 0.0) {
2524 dec2 = MSVCRT_log10(number + 1e-10);
2525 if (-dec2 <= ndigits) dec2 = 0;
2528 /* If requested digits is zero or less, we will need to truncate
2529 * the returned string */
2530 if (ndigits < 1) {
2531 stop += ndigits;
2534 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
2535 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
2536 if (!first) first = ptr2;
2537 if ((ptr1 - buf) < stop) {
2538 *ptr2++ = *ptr1++;
2539 } else {
2540 ptr1++;
2542 dec1++;
2545 if (ndigits > 0) {
2546 ptr1++;
2547 if (!first) {
2548 while (*ptr1 == '0') { /* Process leading zeroes */
2549 *ptr2++ = *ptr1++;
2550 dec1--;
2553 while (*ptr1 != '\0') {
2554 if (!first) first = ptr2;
2555 *ptr2++ = *ptr1++;
2559 *ptr2 = '\0';
2561 /* We never found a non-zero digit, then our number is either
2562 * smaller than the requested precision, or 0.0 */
2563 if (!first) {
2564 if (number > 0.0) {
2565 first = ptr2;
2566 } else {
2567 first = data->efcvt_buffer;
2568 dec1 = 0;
2572 *decpt = dec2 ? dec2 : dec1;
2573 return first;
2576 /***********************************************************************
2577 * _fcvt_s (MSVCRT.@)
2579 int CDECL MSVCRT__fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int *decpt, int *sign)
2581 int stop, dec1, dec2;
2582 char *ptr1, *ptr2, *first;
2583 char buf[80]; /* ought to be enough */
2584 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
2586 if (!outbuffer || !decpt || !sign || size == 0)
2588 *_errno() = EINVAL;
2589 return EINVAL;
2592 if (number < 0)
2594 *sign = 1;
2595 number = -number;
2596 } else *sign = 0;
2598 stop = MSVCRT__snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
2599 ptr1 = buf;
2600 ptr2 = outbuffer;
2601 first = NULL;
2602 dec1 = 0;
2603 dec2 = 0;
2605 /* For numbers below the requested resolution, work out where
2606 the decimal point will be rather than finding it in the string */
2607 if (number < 1.0 && number > 0.0) {
2608 dec2 = MSVCRT_log10(number + 1e-10);
2609 if (-dec2 <= ndigits) dec2 = 0;
2612 /* If requested digits is zero or less, we will need to truncate
2613 * the returned string */
2614 if (ndigits < 1) {
2615 stop += ndigits;
2618 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
2619 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
2620 if (!first) first = ptr2;
2621 if ((ptr1 - buf) < stop) {
2622 if (size > 1) {
2623 *ptr2++ = *ptr1++;
2624 size--;
2626 } else {
2627 ptr1++;
2629 dec1++;
2632 if (ndigits > 0) {
2633 ptr1++;
2634 if (!first) {
2635 while (*ptr1 == '0') { /* Process leading zeroes */
2636 if (number == 0.0 && size > 1) {
2637 *ptr2++ = '0';
2638 size--;
2640 ptr1++;
2641 dec1--;
2644 while (*ptr1 != '\0') {
2645 if (!first) first = ptr2;
2646 if (size > 1) {
2647 *ptr2++ = *ptr1++;
2648 size--;
2653 *ptr2 = '\0';
2655 /* We never found a non-zero digit, then our number is either
2656 * smaller than the requested precision, or 0.0 */
2657 if (!first && (number <= 0.0))
2658 dec1 = 0;
2660 *decpt = dec2 ? dec2 : dec1;
2661 return 0;
2664 /***********************************************************************
2665 * _gcvt (MSVCRT.@)
2667 char * CDECL MSVCRT__gcvt( double number, int ndigit, char *buff )
2669 if(!buff) {
2670 *_errno() = EINVAL;
2671 return NULL;
2674 if(ndigit < 0) {
2675 *_errno() = ERANGE;
2676 return NULL;
2679 MSVCRT_sprintf(buff, "%.*g", ndigit, number);
2680 return buff;
2683 /***********************************************************************
2684 * _gcvt_s (MSVCRT.@)
2686 int CDECL MSVCRT__gcvt_s(char *buff, size_t size, double number, int digits)
2688 int len;
2690 if(!buff) {
2691 *_errno() = EINVAL;
2692 return EINVAL;
2695 if( digits<0 || digits>=size) {
2696 if(size)
2697 buff[0] = '\0';
2699 *_errno() = ERANGE;
2700 return ERANGE;
2703 len = MSVCRT__scprintf("%.*g", digits, number);
2704 if(len > size) {
2705 buff[0] = '\0';
2706 *_errno() = ERANGE;
2707 return ERANGE;
2710 MSVCRT_sprintf(buff, "%.*g", digits, number);
2711 return 0;
2714 #include <stdlib.h> /* div_t, ldiv_t */
2716 /*********************************************************************
2717 * div (MSVCRT.@)
2718 * VERSION
2719 * [i386] Windows binary compatible - returns the struct in eax/edx.
2721 #ifdef __i386__
2722 unsigned __int64 CDECL MSVCRT_div(int num, int denom)
2724 union {
2725 div_t div;
2726 unsigned __int64 uint64;
2727 } ret;
2729 ret.div.quot = num / denom;
2730 ret.div.rem = num % denom;
2731 return ret.uint64;
2733 #else
2734 /*********************************************************************
2735 * div (MSVCRT.@)
2736 * VERSION
2737 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2739 div_t CDECL MSVCRT_div(int num, int denom)
2741 div_t ret;
2743 ret.quot = num / denom;
2744 ret.rem = num % denom;
2745 return ret;
2747 #endif /* ifdef __i386__ */
2750 /*********************************************************************
2751 * ldiv (MSVCRT.@)
2752 * VERSION
2753 * [i386] Windows binary compatible - returns the struct in eax/edx.
2755 #ifdef __i386__
2756 unsigned __int64 CDECL MSVCRT_ldiv(__msvcrt_long num, __msvcrt_long denom)
2758 union {
2759 ldiv_t ldiv;
2760 unsigned __int64 uint64;
2761 } ret;
2763 ret.ldiv.quot = num / denom;
2764 ret.ldiv.rem = num % denom;
2765 return ret.uint64;
2767 #else
2768 /*********************************************************************
2769 * ldiv (MSVCRT.@)
2770 * VERSION
2771 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2773 ldiv_t CDECL MSVCRT_ldiv(__msvcrt_long num, __msvcrt_long denom)
2775 ldiv_t ret;
2777 ret.quot = num / denom;
2778 ret.rem = num % denom;
2779 return ret;
2781 #endif /* ifdef __i386__ */
2783 #if _MSVCR_VER>=100
2784 /*********************************************************************
2785 * lldiv (MSVCR100.@)
2787 lldiv_t CDECL MSVCRT_lldiv(__int64 num, __int64 denom)
2789 lldiv_t ret;
2791 ret.quot = num / denom;
2792 ret.rem = num % denom;
2794 return ret;
2796 #endif
2798 #ifdef __i386__
2800 /*********************************************************************
2801 * _adjust_fdiv (MSVCRT.@)
2802 * Used by the MSVC compiler to work around the Pentium FDIV bug.
2804 int MSVCRT__adjust_fdiv = 0;
2806 /***********************************************************************
2807 * _adj_fdiv_m16i (MSVCRT.@)
2809 * NOTE
2810 * I _think_ this function is intended to work around the Pentium
2811 * fdiv bug.
2813 void __stdcall _adj_fdiv_m16i( short arg )
2815 TRACE("(): stub\n");
2818 /***********************************************************************
2819 * _adj_fdiv_m32 (MSVCRT.@)
2821 * NOTE
2822 * I _think_ this function is intended to work around the Pentium
2823 * fdiv bug.
2825 void __stdcall _adj_fdiv_m32( unsigned int arg )
2827 TRACE("(): stub\n");
2830 /***********************************************************************
2831 * _adj_fdiv_m32i (MSVCRT.@)
2833 * NOTE
2834 * I _think_ this function is intended to work around the Pentium
2835 * fdiv bug.
2837 void __stdcall _adj_fdiv_m32i( int arg )
2839 TRACE("(): stub\n");
2842 /***********************************************************************
2843 * _adj_fdiv_m64 (MSVCRT.@)
2845 * NOTE
2846 * I _think_ this function is intended to work around the Pentium
2847 * fdiv bug.
2849 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
2851 TRACE("(): stub\n");
2854 /***********************************************************************
2855 * _adj_fdiv_r (MSVCRT.@)
2856 * FIXME
2857 * This function is likely to have the wrong number of arguments.
2859 * NOTE
2860 * I _think_ this function is intended to work around the Pentium
2861 * fdiv bug.
2863 void _adj_fdiv_r(void)
2865 TRACE("(): stub\n");
2868 /***********************************************************************
2869 * _adj_fdivr_m16i (MSVCRT.@)
2871 * NOTE
2872 * I _think_ this function is intended to work around the Pentium
2873 * fdiv bug.
2875 void __stdcall _adj_fdivr_m16i( short arg )
2877 TRACE("(): stub\n");
2880 /***********************************************************************
2881 * _adj_fdivr_m32 (MSVCRT.@)
2883 * NOTE
2884 * I _think_ this function is intended to work around the Pentium
2885 * fdiv bug.
2887 void __stdcall _adj_fdivr_m32( unsigned int arg )
2889 TRACE("(): stub\n");
2892 /***********************************************************************
2893 * _adj_fdivr_m32i (MSVCRT.@)
2895 * NOTE
2896 * I _think_ this function is intended to work around the Pentium
2897 * fdiv bug.
2899 void __stdcall _adj_fdivr_m32i( int arg )
2901 TRACE("(): stub\n");
2904 /***********************************************************************
2905 * _adj_fdivr_m64 (MSVCRT.@)
2907 * NOTE
2908 * I _think_ this function is intended to work around the Pentium
2909 * fdiv bug.
2911 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
2913 TRACE("(): stub\n");
2916 /***********************************************************************
2917 * _adj_fpatan (MSVCRT.@)
2918 * FIXME
2919 * This function is likely to have the wrong number of arguments.
2921 * NOTE
2922 * I _think_ this function is intended to work around the Pentium
2923 * fdiv bug.
2925 void _adj_fpatan(void)
2927 TRACE("(): stub\n");
2930 /***********************************************************************
2931 * _adj_fprem (MSVCRT.@)
2932 * FIXME
2933 * This function is likely to have the wrong number of arguments.
2935 * NOTE
2936 * I _think_ this function is intended to work around the Pentium
2937 * fdiv bug.
2939 void _adj_fprem(void)
2941 TRACE("(): stub\n");
2944 /***********************************************************************
2945 * _adj_fprem1 (MSVCRT.@)
2946 * FIXME
2947 * This function is likely to have the wrong number of arguments.
2949 * NOTE
2950 * I _think_ this function is intended to work around the Pentium
2951 * fdiv bug.
2953 void _adj_fprem1(void)
2955 TRACE("(): stub\n");
2958 /***********************************************************************
2959 * _adj_fptan (MSVCRT.@)
2960 * FIXME
2961 * This function is likely to have the wrong number of arguments.
2963 * NOTE
2964 * I _think_ this function is intended to work around the Pentium
2965 * fdiv bug.
2967 void _adj_fptan(void)
2969 TRACE("(): stub\n");
2972 /***********************************************************************
2973 * _safe_fdiv (MSVCRT.@)
2974 * FIXME
2975 * This function is likely to have the wrong number of arguments.
2977 * NOTE
2978 * I _think_ this function is intended to work around the Pentium
2979 * fdiv bug.
2981 void _safe_fdiv(void)
2983 TRACE("(): stub\n");
2986 /***********************************************************************
2987 * _safe_fdivr (MSVCRT.@)
2988 * FIXME
2989 * This function is likely to have the wrong number of arguments.
2991 * NOTE
2992 * I _think_ this function is intended to work around the Pentium
2993 * fdiv bug.
2995 void _safe_fdivr(void)
2997 TRACE("(): stub\n");
3000 /***********************************************************************
3001 * _safe_fprem (MSVCRT.@)
3002 * FIXME
3003 * This function is likely to have the wrong number of arguments.
3005 * NOTE
3006 * I _think_ this function is intended to work around the Pentium
3007 * fdiv bug.
3009 void _safe_fprem(void)
3011 TRACE("(): stub\n");
3014 /***********************************************************************
3015 * _safe_fprem1 (MSVCRT.@)
3017 * FIXME
3018 * This function is likely to have the wrong number of arguments.
3020 * NOTE
3021 * I _think_ this function is intended to work around the Pentium
3022 * fdiv bug.
3024 void _safe_fprem1(void)
3026 TRACE("(): stub\n");
3029 /***********************************************************************
3030 * __libm_sse2_acos (MSVCRT.@)
3032 void __cdecl MSVCRT___libm_sse2_acos(void)
3034 double d;
3035 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3036 d = MSVCRT_acos( d );
3037 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3040 /***********************************************************************
3041 * __libm_sse2_acosf (MSVCRT.@)
3043 void __cdecl MSVCRT___libm_sse2_acosf(void)
3045 float f;
3046 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3047 f = MSVCRT_acosf( f );
3048 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3051 /***********************************************************************
3052 * __libm_sse2_asin (MSVCRT.@)
3054 void __cdecl MSVCRT___libm_sse2_asin(void)
3056 double d;
3057 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3058 d = MSVCRT_asin( d );
3059 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3062 /***********************************************************************
3063 * __libm_sse2_asinf (MSVCRT.@)
3065 void __cdecl MSVCRT___libm_sse2_asinf(void)
3067 float f;
3068 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3069 f = MSVCRT_asinf( f );
3070 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3073 /***********************************************************************
3074 * __libm_sse2_atan (MSVCRT.@)
3076 void __cdecl MSVCRT___libm_sse2_atan(void)
3078 double d;
3079 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3080 d = MSVCRT_atan( d );
3081 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3084 /***********************************************************************
3085 * __libm_sse2_atan2 (MSVCRT.@)
3087 void __cdecl MSVCRT___libm_sse2_atan2(void)
3089 double d1, d2;
3090 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
3091 d1 = MSVCRT_atan2( d1, d2 );
3092 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
3095 /***********************************************************************
3096 * __libm_sse2_atanf (MSVCRT.@)
3098 void __cdecl MSVCRT___libm_sse2_atanf(void)
3100 float f;
3101 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3102 f = MSVCRT_atanf( f );
3103 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3106 /***********************************************************************
3107 * __libm_sse2_cos (MSVCRT.@)
3109 void __cdecl MSVCRT___libm_sse2_cos(void)
3111 double d;
3112 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3113 d = MSVCRT_cos( d );
3114 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3117 /***********************************************************************
3118 * __libm_sse2_cosf (MSVCRT.@)
3120 void __cdecl MSVCRT___libm_sse2_cosf(void)
3122 float f;
3123 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3124 f = MSVCRT_cosf( f );
3125 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3128 /***********************************************************************
3129 * __libm_sse2_exp (MSVCRT.@)
3131 void __cdecl MSVCRT___libm_sse2_exp(void)
3133 double d;
3134 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3135 d = MSVCRT_exp( d );
3136 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3139 /***********************************************************************
3140 * __libm_sse2_expf (MSVCRT.@)
3142 void __cdecl MSVCRT___libm_sse2_expf(void)
3144 float f;
3145 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3146 f = MSVCRT_expf( f );
3147 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3150 /***********************************************************************
3151 * __libm_sse2_log (MSVCRT.@)
3153 void __cdecl MSVCRT___libm_sse2_log(void)
3155 double d;
3156 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3157 d = MSVCRT_log( d );
3158 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3161 /***********************************************************************
3162 * __libm_sse2_log10 (MSVCRT.@)
3164 void __cdecl MSVCRT___libm_sse2_log10(void)
3166 double d;
3167 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3168 d = MSVCRT_log10( d );
3169 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3172 /***********************************************************************
3173 * __libm_sse2_log10f (MSVCRT.@)
3175 void __cdecl MSVCRT___libm_sse2_log10f(void)
3177 float f;
3178 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3179 f = MSVCRT_log10f( f );
3180 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3183 /***********************************************************************
3184 * __libm_sse2_logf (MSVCRT.@)
3186 void __cdecl MSVCRT___libm_sse2_logf(void)
3188 float f;
3189 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3190 f = MSVCRT_logf( f );
3191 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3194 /***********************************************************************
3195 * __libm_sse2_pow (MSVCRT.@)
3197 void __cdecl MSVCRT___libm_sse2_pow(void)
3199 double d1, d2;
3200 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
3201 d1 = MSVCRT_pow( d1, d2 );
3202 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
3205 /***********************************************************************
3206 * __libm_sse2_powf (MSVCRT.@)
3208 void __cdecl MSVCRT___libm_sse2_powf(void)
3210 float f1, f2;
3211 __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
3212 f1 = MSVCRT_powf( f1, f2 );
3213 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
3216 /***********************************************************************
3217 * __libm_sse2_sin (MSVCRT.@)
3219 void __cdecl MSVCRT___libm_sse2_sin(void)
3221 double d;
3222 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3223 d = MSVCRT_sin( d );
3224 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3227 /***********************************************************************
3228 * __libm_sse2_sinf (MSVCRT.@)
3230 void __cdecl MSVCRT___libm_sse2_sinf(void)
3232 float f;
3233 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3234 f = MSVCRT_sinf( f );
3235 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3238 /***********************************************************************
3239 * __libm_sse2_tan (MSVCRT.@)
3241 void __cdecl MSVCRT___libm_sse2_tan(void)
3243 double d;
3244 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3245 d = MSVCRT_tan( d );
3246 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3249 /***********************************************************************
3250 * __libm_sse2_tanf (MSVCRT.@)
3252 void __cdecl MSVCRT___libm_sse2_tanf(void)
3254 float f;
3255 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3256 f = MSVCRT_tanf( f );
3257 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3260 /***********************************************************************
3261 * __libm_sse2_sqrt_precise (MSVCR110.@)
3263 void __cdecl MSVCRT___libm_sse2_sqrt_precise(void)
3265 double d;
3266 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3267 d = MSVCRT_sqrt( d );
3268 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3271 #endif /* __i386__ */
3273 /*********************************************************************
3274 * cbrt (MSVCR120.@)
3276 double CDECL MSVCR120_cbrt(double x)
3278 return unix_funcs->cbrt( x );
3281 /*********************************************************************
3282 * cbrtf (MSVCR120.@)
3284 float CDECL MSVCR120_cbrtf(float x)
3286 return unix_funcs->cbrtf( x );
3289 /*********************************************************************
3290 * cbrtl (MSVCR120.@)
3292 LDOUBLE CDECL MSVCR120_cbrtl(LDOUBLE x)
3294 return MSVCR120_cbrt(x);
3297 /*********************************************************************
3298 * exp2 (MSVCR120.@)
3300 double CDECL MSVCR120_exp2(double x)
3302 double ret = unix_funcs->exp2( x );
3303 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3304 return ret;
3307 /*********************************************************************
3308 * exp2f (MSVCR120.@)
3310 float CDECL MSVCR120_exp2f(float x)
3312 float ret = unix_funcs->exp2f( x );
3313 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3314 return ret;
3317 /*********************************************************************
3318 * exp2l (MSVCR120.@)
3320 LDOUBLE CDECL MSVCR120_exp2l(LDOUBLE x)
3322 return MSVCR120_exp2(x);
3325 /*********************************************************************
3326 * expm1 (MSVCR120.@)
3328 double CDECL MSVCR120_expm1(double x)
3330 double ret = unix_funcs->expm1( x );
3331 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3332 return ret;
3335 /*********************************************************************
3336 * expm1f (MSVCR120.@)
3338 float CDECL MSVCR120_expm1f(float x)
3340 float ret = unix_funcs->expm1f( x );
3341 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3342 return ret;
3345 /*********************************************************************
3346 * expm1l (MSVCR120.@)
3348 LDOUBLE CDECL MSVCR120_expm1l(LDOUBLE x)
3350 return MSVCR120_expm1(x);
3353 /*********************************************************************
3354 * log1p (MSVCR120.@)
3356 double CDECL MSVCR120_log1p(double x)
3358 if (x < -1) *_errno() = EDOM;
3359 else if (x == -1) *_errno() = ERANGE;
3360 return unix_funcs->log1p( x );
3363 /*********************************************************************
3364 * log1pf (MSVCR120.@)
3366 float CDECL MSVCR120_log1pf(float x)
3368 if (x < -1) *_errno() = EDOM;
3369 else if (x == -1) *_errno() = ERANGE;
3370 return unix_funcs->log1pf( x );
3373 /*********************************************************************
3374 * log1pl (MSVCR120.@)
3376 LDOUBLE CDECL MSVCR120_log1pl(LDOUBLE x)
3378 return MSVCR120_log1p(x);
3381 /*********************************************************************
3382 * log2 (MSVCR120.@)
3384 double CDECL MSVCR120_log2(double x)
3386 if (x < 0) *_errno() = EDOM;
3387 else if (x == 0) *_errno() = ERANGE;
3388 return unix_funcs->log2( x );
3391 /*********************************************************************
3392 * log2f (MSVCR120.@)
3394 float CDECL MSVCR120_log2f(float x)
3396 if (x < 0) *_errno() = EDOM;
3397 else if (x == 0) *_errno() = ERANGE;
3398 return unix_funcs->log2f( x );
3401 /*********************************************************************
3402 * log2l (MSVCR120.@)
3404 LDOUBLE CDECL MSVCR120_log2l(LDOUBLE x)
3406 return MSVCR120_log2(x);
3409 /*********************************************************************
3410 * rint (MSVCR120.@)
3412 double CDECL MSVCR120_rint(double x)
3414 return unix_funcs->rint(x);
3417 /*********************************************************************
3418 * rintf (MSVCR120.@)
3420 float CDECL MSVCR120_rintf(float x)
3422 return unix_funcs->rintf(x);
3425 /*********************************************************************
3426 * rintl (MSVCR120.@)
3428 LDOUBLE CDECL MSVCR120_rintl(LDOUBLE x)
3430 return MSVCR120_rint(x);
3433 /*********************************************************************
3434 * lrint (MSVCR120.@)
3436 __msvcrt_long CDECL MSVCR120_lrint(double x)
3438 return unix_funcs->lrint( x );
3441 /*********************************************************************
3442 * lrintf (MSVCR120.@)
3444 __msvcrt_long CDECL MSVCR120_lrintf(float x)
3446 return unix_funcs->lrintf( x );
3449 /*********************************************************************
3450 * lrintl (MSVCR120.@)
3452 __msvcrt_long CDECL MSVCR120_lrintl(LDOUBLE x)
3454 return MSVCR120_lrint(x);
3457 /*********************************************************************
3458 * llrint (MSVCR120.@)
3460 __int64 CDECL MSVCR120_llrint(double x)
3462 return unix_funcs->llrint( x );
3465 /*********************************************************************
3466 * llrintf (MSVCR120.@)
3468 __int64 CDECL MSVCR120_llrintf(float x)
3470 return unix_funcs->llrintf( x );
3473 /*********************************************************************
3474 * rintl (MSVCR120.@)
3476 __int64 CDECL MSVCR120_llrintl(LDOUBLE x)
3478 return MSVCR120_llrint(x);
3481 #if _MSVCR_VER>=120
3483 /*********************************************************************
3484 * round (MSVCR120.@)
3486 double CDECL MSVCR120_round(double x)
3488 return unix_funcs->round(x);
3491 /*********************************************************************
3492 * roundf (MSVCR120.@)
3494 float CDECL MSVCR120_roundf(float x)
3496 return unix_funcs->roundf(x);
3499 /*********************************************************************
3500 * roundl (MSVCR120.@)
3502 LDOUBLE CDECL MSVCR120_roundl(LDOUBLE x)
3504 return MSVCR120_round(x);
3507 /*********************************************************************
3508 * lround (MSVCR120.@)
3510 __msvcrt_long CDECL MSVCR120_lround(double x)
3512 return unix_funcs->lround( x );
3515 /*********************************************************************
3516 * lroundf (MSVCR120.@)
3518 __msvcrt_long CDECL MSVCR120_lroundf(float x)
3520 return unix_funcs->lroundf( x );
3523 /*********************************************************************
3524 * lroundl (MSVCR120.@)
3526 __msvcrt_long CDECL MSVCR120_lroundl(LDOUBLE x)
3528 return MSVCR120_lround(x);
3531 /*********************************************************************
3532 * llround (MSVCR120.@)
3534 __int64 CDECL MSVCR120_llround(double x)
3536 return unix_funcs->llround( x );
3539 /*********************************************************************
3540 * llroundf (MSVCR120.@)
3542 __int64 CDECL MSVCR120_llroundf(float x)
3544 return unix_funcs->llroundf( x );
3547 /*********************************************************************
3548 * roundl (MSVCR120.@)
3550 __int64 CDECL MSVCR120_llroundl(LDOUBLE x)
3552 return MSVCR120_llround(x);
3555 /*********************************************************************
3556 * trunc (MSVCR120.@)
3558 double CDECL MSVCR120_trunc(double x)
3560 return unix_funcs->trunc(x);
3563 /*********************************************************************
3564 * truncf (MSVCR120.@)
3566 float CDECL MSVCR120_truncf(float x)
3568 return unix_funcs->truncf(x);
3571 /*********************************************************************
3572 * truncl (MSVCR120.@)
3574 LDOUBLE CDECL MSVCR120_truncl(LDOUBLE x)
3576 return MSVCR120_trunc(x);
3579 /*********************************************************************
3580 * _dclass (MSVCR120.@)
3582 * Copied from musl: src/math/__fpclassify.c
3584 short CDECL MSVCR120__dclass(double x)
3586 union { double f; UINT64 i; } u = { x };
3587 int e = u.i >> 52 & 0x7ff;
3589 if (!e) return u.i << 1 ? MSVCRT_FP_SUBNORMAL : MSVCRT_FP_ZERO;
3590 if (e == 0x7ff) return (u.i << 12) ? MSVCRT_FP_NAN : MSVCRT_FP_INFINITE;
3591 return MSVCRT_FP_NORMAL;
3594 /*********************************************************************
3595 * _fdclass (MSVCR120.@)
3597 * Copied from musl: src/math/__fpclassifyf.c
3599 short CDECL MSVCR120__fdclass(float x)
3601 union { float f; UINT32 i; } u = { x };
3602 int e = u.i >> 23 & 0xff;
3604 if (!e) return u.i << 1 ? MSVCRT_FP_SUBNORMAL : MSVCRT_FP_ZERO;
3605 if (e == 0xff) return u.i << 9 ? MSVCRT_FP_NAN : MSVCRT_FP_INFINITE;
3606 return MSVCRT_FP_NORMAL;
3609 /*********************************************************************
3610 * _ldclass (MSVCR120.@)
3612 short CDECL MSVCR120__ldclass(LDOUBLE x)
3614 return MSVCR120__dclass(x);
3617 /*********************************************************************
3618 * _dtest (MSVCR120.@)
3620 short CDECL MSVCR120__dtest(double *x)
3622 return MSVCR120__dclass(*x);
3625 /*********************************************************************
3626 * _fdtest (MSVCR120.@)
3628 short CDECL MSVCR120__fdtest(float *x)
3630 return MSVCR120__fdclass(*x);
3633 /*********************************************************************
3634 * _ldtest (MSVCR120.@)
3636 short CDECL MSVCR120__ldtest(LDOUBLE *x)
3638 return MSVCR120__dclass(*x);
3641 /*********************************************************************
3642 * erf (MSVCR120.@)
3644 double CDECL MSVCR120_erf(double x)
3646 return unix_funcs->erf( x );
3649 /*********************************************************************
3650 * erff (MSVCR120.@)
3652 float CDECL MSVCR120_erff(float x)
3654 return unix_funcs->erff( x );
3657 /*********************************************************************
3658 * erfl (MSVCR120.@)
3660 LDOUBLE CDECL MSVCR120_erfl(LDOUBLE x)
3662 return MSVCR120_erf(x);
3665 /*********************************************************************
3666 * erfc (MSVCR120.@)
3668 double CDECL MSVCR120_erfc(double x)
3670 return unix_funcs->erfc( x );
3673 /*********************************************************************
3674 * erfcf (MSVCR120.@)
3676 float CDECL MSVCR120_erfcf(float x)
3678 return unix_funcs->erfcf( x );
3681 /*********************************************************************
3682 * erfcl (MSVCR120.@)
3684 LDOUBLE CDECL MSVCR120_erfcl(LDOUBLE x)
3686 return MSVCR120_erfc(x);
3689 /*********************************************************************
3690 * fmaxf (MSVCR120.@)
3692 float CDECL MSVCR120_fmaxf(float x, float y)
3694 if(isnan(x))
3695 return y;
3696 if(isnan(y))
3697 return x;
3698 if(x==0 && y==0)
3699 return signbit(x) ? y : x;
3700 return x<y ? y : x;
3703 /*********************************************************************
3704 * fmax (MSVCR120.@)
3706 double CDECL MSVCR120_fmax(double x, double y)
3708 if(isnan(x))
3709 return y;
3710 if(isnan(y))
3711 return x;
3712 if(x==0 && y==0)
3713 return signbit(x) ? y : x;
3714 return x<y ? y : x;
3717 /*********************************************************************
3718 * fdimf (MSVCR120.@)
3720 float CDECL MSVCR120_fdimf(float x, float y)
3722 if(isnan(x))
3723 return x;
3724 if(isnan(y))
3725 return y;
3726 return x>y ? x-y : 0;
3729 /*********************************************************************
3730 * fdim (MSVCR120.@)
3732 double CDECL MSVCR120_fdim(double x, double y)
3734 if(isnan(x))
3735 return x;
3736 if(isnan(y))
3737 return y;
3738 return x>y ? x-y : 0;
3741 /*********************************************************************
3742 * _fdsign (MSVCR120.@)
3744 int CDECL MSVCR120__fdsign(float x)
3746 union { float f; UINT32 i; } u = { x };
3747 return (u.i >> 16) & 0x8000;
3750 /*********************************************************************
3751 * _dsign (MSVCR120.@)
3753 int CDECL MSVCR120__dsign(double x)
3755 union { double f; UINT64 i; } u = { x };
3756 return (u.i >> 48) & 0x8000;
3760 /*********************************************************************
3761 * _dpcomp (MSVCR120.@)
3763 int CDECL MSVCR120__dpcomp(double x, double y)
3765 if(isnan(x) || isnan(y))
3766 return 0;
3768 if(x == y) return 2;
3769 return x < y ? 1 : 4;
3772 /*********************************************************************
3773 * _fdpcomp (MSVCR120.@)
3775 int CDECL MSVCR120__fdpcomp(float x, float y)
3777 return MSVCR120__dpcomp(x, y);
3780 /*********************************************************************
3781 * fminf (MSVCR120.@)
3783 float CDECL MSVCR120_fminf(float x, float y)
3785 if(isnan(x))
3786 return y;
3787 if(isnan(y))
3788 return x;
3789 if(x==0 && y==0)
3790 return signbit(x) ? x : y;
3791 return x<y ? x : y;
3794 /*********************************************************************
3795 * fmin (MSVCR120.@)
3797 double CDECL MSVCR120_fmin(double x, double y)
3799 if(isnan(x))
3800 return y;
3801 if(isnan(y))
3802 return x;
3803 if(x==0 && y==0)
3804 return signbit(x) ? x : y;
3805 return x<y ? x : y;
3808 /*********************************************************************
3809 * asinh (MSVCR120.@)
3811 double CDECL MSVCR120_asinh(double x)
3813 return unix_funcs->asinh( x );
3816 /*********************************************************************
3817 * asinhf (MSVCR120.@)
3819 float CDECL MSVCR120_asinhf(float x)
3821 return unix_funcs->asinhf( x );
3824 /*********************************************************************
3825 * asinhl (MSVCR120.@)
3827 LDOUBLE CDECL MSVCR120_asinhl(LDOUBLE x)
3829 return MSVCR120_asinh(x);
3832 /*********************************************************************
3833 * acosh (MSVCR120.@)
3835 double CDECL MSVCR120_acosh(double x)
3837 if (x < 1)
3839 fenv_t env;
3841 *_errno() = EDOM;
3842 MSVCRT_fegetenv(&env);
3843 env._Fe_stat |= FE_INVALID;
3844 MSVCRT_fesetenv(&env);
3845 return NAN;
3847 return unix_funcs->acosh( x );
3850 /*********************************************************************
3851 * acoshf (MSVCR120.@)
3853 float CDECL MSVCR120_acoshf(float x)
3855 if (x < 1)
3857 fenv_t env;
3859 *_errno() = EDOM;
3860 MSVCRT_fegetenv(&env);
3861 env._Fe_stat |= FE_INVALID;
3862 MSVCRT_fesetenv(&env);
3863 return NAN;
3865 return unix_funcs->acoshf( x );
3868 /*********************************************************************
3869 * acoshl (MSVCR120.@)
3871 LDOUBLE CDECL MSVCR120_acoshl(LDOUBLE x)
3873 return MSVCR120_acosh(x);
3876 /*********************************************************************
3877 * atanh (MSVCR120.@)
3879 double CDECL MSVCR120_atanh(double x)
3881 double ret;
3883 if (x > 1 || x < -1) {
3884 fenv_t env;
3886 *_errno() = EDOM;
3888 /* on Linux atanh returns -NAN in this case */
3889 MSVCRT_fegetenv(&env);
3890 env._Fe_stat |= FE_INVALID;
3891 MSVCRT_fesetenv(&env);
3892 return NAN;
3894 ret = unix_funcs->atanh( x );
3896 if (!isfinite(ret)) *_errno() = ERANGE;
3897 return ret;
3900 /*********************************************************************
3901 * atanhf (MSVCR120.@)
3903 float CDECL MSVCR120_atanhf(float x)
3905 float ret;
3907 if (x > 1 || x < -1) {
3908 fenv_t env;
3910 *_errno() = EDOM;
3912 MSVCRT_fegetenv(&env);
3913 env._Fe_stat |= FE_INVALID;
3914 MSVCRT_fesetenv(&env);
3915 return NAN;
3918 ret = unix_funcs->atanh( x );
3920 if (!isfinite(ret)) *_errno() = ERANGE;
3921 return ret;
3924 /*********************************************************************
3925 * atanhl (MSVCR120.@)
3927 LDOUBLE CDECL MSVCR120_atanhl(LDOUBLE x)
3929 return MSVCR120_atanh(x);
3932 #endif /* _MSVCR_VER>=120 */
3934 /*********************************************************************
3935 * _scalb (MSVCRT.@)
3936 * scalbn (MSVCR120.@)
3937 * scalbln (MSVCR120.@)
3939 double CDECL MSVCRT__scalb(double num, __msvcrt_long power)
3941 return MSVCRT_ldexp(num, power);
3944 /*********************************************************************
3945 * _scalbf (MSVCRT.@)
3946 * scalbnf (MSVCR120.@)
3947 * scalblnf (MSVCR120.@)
3949 float CDECL MSVCRT__scalbf(float num, __msvcrt_long power)
3951 return MSVCRT_ldexp(num, power);
3954 #if _MSVCR_VER>=120
3956 /*********************************************************************
3957 * scalbnl (MSVCR120.@)
3958 * scalblnl (MSVCR120.@)
3960 LDOUBLE CDECL MSVCR120_scalbnl(LDOUBLE num, __msvcrt_long power)
3962 return MSVCRT__scalb(num, power);
3965 /*********************************************************************
3966 * remainder (MSVCR120.@)
3968 double CDECL MSVCR120_remainder(double x, double y)
3970 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3971 if(!isfinite(x)) *_errno() = EDOM;
3972 if(isnan(y) || y==0.0) *_errno() = EDOM;
3973 return unix_funcs->remainder( x, y );
3976 /*********************************************************************
3977 * remainderf (MSVCR120.@)
3979 float CDECL MSVCR120_remainderf(float x, float y)
3981 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3982 if(!isfinite(x)) *_errno() = EDOM;
3983 if(isnan(y) || y==0.0f) *_errno() = EDOM;
3984 return unix_funcs->remainderf( x, y );
3987 /*********************************************************************
3988 * remainderl (MSVCR120.@)
3990 LDOUBLE CDECL MSVCR120_remainderl(LDOUBLE x, LDOUBLE y)
3992 return MSVCR120_remainder(x, y);
3995 /*********************************************************************
3996 * remquo (MSVCR120.@)
3998 double CDECL MSVCR120_remquo(double x, double y, int *quo)
4000 if(!isfinite(x)) *_errno() = EDOM;
4001 if(isnan(y) || y==0.0) *_errno() = EDOM;
4002 return unix_funcs->remquo( x, y, quo );
4005 /*********************************************************************
4006 * remquof (MSVCR120.@)
4008 float CDECL MSVCR120_remquof(float x, float y, int *quo)
4010 if(!isfinite(x)) *_errno() = EDOM;
4011 if(isnan(y) || y==0.0f) *_errno() = EDOM;
4012 return unix_funcs->remquof( x, y, quo );
4015 /*********************************************************************
4016 * remquol (MSVCR120.@)
4018 LDOUBLE CDECL MSVCR120_remquol(LDOUBLE x, LDOUBLE y, int *quo)
4020 return MSVCR120_remquo(x, y, quo);
4023 /*********************************************************************
4024 * lgamma (MSVCR120.@)
4026 double CDECL MSVCR120_lgamma(double x)
4028 return unix_funcs->lgamma( x );
4031 /*********************************************************************
4032 * lgammaf (MSVCR120.@)
4034 float CDECL MSVCR120_lgammaf(float x)
4036 return unix_funcs->lgammaf( x );
4039 /*********************************************************************
4040 * lgammal (MSVCR120.@)
4042 LDOUBLE CDECL MSVCR120_lgammal(LDOUBLE x)
4044 return MSVCR120_lgamma(x);
4047 /*********************************************************************
4048 * tgamma (MSVCR120.@)
4050 double CDECL MSVCR120_tgamma(double x)
4052 return unix_funcs->tgamma( x );
4055 /*********************************************************************
4056 * tgammaf (MSVCR120.@)
4058 float CDECL MSVCR120_tgammaf(float x)
4060 return unix_funcs->tgammaf( x );
4063 /*********************************************************************
4064 * nan (MSVCR120.@)
4066 double CDECL MSVCR120_nan(const char *tagp)
4068 /* Windows ignores input (MSDN) */
4069 return NAN;
4072 /*********************************************************************
4073 * nanf (MSVCR120.@)
4075 float CDECL MSVCR120_nanf(const char *tagp)
4077 return NAN;
4080 /*********************************************************************
4081 * _except1 (MSVCR120.@)
4082 * TODO:
4083 * - find meaning of ignored cw and operation bits
4084 * - unk parameter
4086 double CDECL _except1(DWORD fpe, _FP_OPERATION_CODE op, double arg, double res, DWORD cw, void *unk)
4088 ULONG_PTR exception_arg;
4089 DWORD exception = 0;
4090 fenv_t env;
4091 DWORD fpword = 0;
4092 WORD operation;
4094 TRACE("(%x %x %lf %lf %x %p)\n", fpe, op, arg, res, cw, unk);
4096 #ifdef _WIN64
4097 cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
4098 #endif
4099 operation = op << 5;
4100 exception_arg = (ULONG_PTR)&operation;
4102 MSVCRT_fegetenv(&env);
4104 if (fpe & 0x1) { /* overflow */
4105 if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
4106 /* 32-bit version also sets SW_INEXACT here */
4107 env._Fe_stat |= FE_OVERFLOW;
4108 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
4109 res = signbit(res) ? -INFINITY : INFINITY;
4110 } else {
4111 exception = EXCEPTION_FLT_OVERFLOW;
4113 } else if (fpe & 0x2) { /* underflow */
4114 if ((fpe == 0x2 && (cw & 0x10)) || (fpe==0x12 && (cw & 0x30))) {
4115 env._Fe_stat |= FE_UNDERFLOW;
4116 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
4117 res = signbit(res) ? -0.0 : 0.0;
4118 } else {
4119 exception = EXCEPTION_FLT_UNDERFLOW;
4121 } else if (fpe & 0x4) { /* zerodivide */
4122 if ((fpe == 0x4 && (cw & 0x4)) || (fpe==0x14 && (cw & 0x24))) {
4123 env._Fe_stat |= FE_DIVBYZERO;
4124 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
4125 } else {
4126 exception = EXCEPTION_FLT_DIVIDE_BY_ZERO;
4128 } else if (fpe & 0x8) { /* invalid */
4129 if (fpe == 0x8 && (cw & 0x1)) {
4130 env._Fe_stat |= FE_INVALID;
4131 } else {
4132 exception = EXCEPTION_FLT_INVALID_OPERATION;
4134 } else if (fpe & 0x10) { /* inexact */
4135 if (fpe == 0x10 && (cw & 0x20)) {
4136 env._Fe_stat |= FE_INEXACT;
4137 } else {
4138 exception = EXCEPTION_FLT_INEXACT_RESULT;
4142 if (exception)
4143 env._Fe_stat = 0;
4144 MSVCRT_fesetenv(&env);
4145 if (exception)
4146 RaiseException(exception, 0, 1, &exception_arg);
4148 if (cw & 0x1) fpword |= MSVCRT__EM_INVALID;
4149 if (cw & 0x2) fpword |= MSVCRT__EM_DENORMAL;
4150 if (cw & 0x4) fpword |= MSVCRT__EM_ZERODIVIDE;
4151 if (cw & 0x8) fpword |= MSVCRT__EM_OVERFLOW;
4152 if (cw & 0x10) fpword |= MSVCRT__EM_UNDERFLOW;
4153 if (cw & 0x20) fpword |= MSVCRT__EM_INEXACT;
4154 switch (cw & 0xc00)
4156 case 0xc00: fpword |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
4157 case 0x800: fpword |= MSVCRT__RC_UP; break;
4158 case 0x400: fpword |= MSVCRT__RC_DOWN; break;
4160 switch (cw & 0x300)
4162 case 0x0: fpword |= MSVCRT__PC_24; break;
4163 case 0x200: fpword |= MSVCRT__PC_53; break;
4164 case 0x300: fpword |= MSVCRT__PC_64; break;
4166 if (cw & 0x1000) fpword |= MSVCRT__IC_AFFINE;
4167 _control87(fpword, 0xffffffff);
4169 return res;
4172 _Dcomplex* CDECL MSVCR120__Cbuild(_Dcomplex *ret, double r, double i)
4174 ret->x = r;
4175 ret->y = i;
4176 return ret;
4179 double CDECL MSVCR120_creal(_Dcomplex z)
4181 return z.x;
4184 /*********************************************************************
4185 * ilogb (MSVCR120.@)
4187 * Copied from musl: src/math/ilogb.c
4189 int CDECL MSVCR120_ilogb(double x)
4191 union { double f; UINT64 i; } u = { x };
4192 int e = u.i >> 52 & 0x7ff;
4194 if (!e)
4196 u.i <<= 12;
4197 if (u.i == 0) return FP_ILOGB0;
4198 /* subnormal x */
4199 for (e = -0x3ff; u.i >> 63 == 0; e--, u.i <<= 1);
4200 return e;
4202 if (e == 0x7ff) return u.i << 12 ? FP_ILOGBNAN : INT_MAX;
4203 return e - 0x3ff;
4206 /*********************************************************************
4207 * ilogbf (MSVCR120.@)
4209 * Copied from musl: src/math/ilogbf.c
4211 int CDECL MSVCR120_ilogbf(float x)
4213 union { float f; UINT32 i; } u = { x };
4214 int e = u.i >> 23 & 0xff;
4216 if (!e)
4218 u.i <<= 9;
4219 if (u.i == 0) return FP_ILOGB0;
4220 /* subnormal x */
4221 for (e = -0x7f; u.i >> 31 == 0; e--, u.i <<= 1);
4222 return e;
4224 if (e == 0xff) return u.i << 9 ? FP_ILOGBNAN : INT_MAX;
4225 return e - 0x7f;
4228 /*********************************************************************
4229 * ilogbl (MSVCR120.@)
4231 int CDECL MSVCR120_ilogbl(LDOUBLE x)
4233 return MSVCR120_ilogb(x);
4236 #endif /* _MSVCR_VER>=120 */