msvcrt: Use GCC-style assembly on Clang MSVC target.
[wine.git] / dlls / msvcrt / math.c
blobe6e837e52c6e0963ddaaaf627750b96415d8a64e
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 * ====================================================
38 #include <complex.h>
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 #undef div
56 #undef ldiv
58 #define _DOMAIN 1 /* domain error in argument */
59 #define _SING 2 /* singularity */
60 #define _OVERFLOW 3 /* range overflow */
61 #define _UNDERFLOW 4 /* range underflow */
63 typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *);
65 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
67 static BOOL sse2_supported;
68 static BOOL sse2_enabled;
70 static const struct unix_funcs *unix_funcs;
72 void msvcrt_init_math( void *module )
74 sse2_supported = sse2_enabled = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
75 __wine_init_unix_lib( module, DLL_PROCESS_ATTACH, NULL, &unix_funcs );
78 /* Copied from musl: src/internal/libm.h */
79 static inline float fp_barrierf(float x)
81 volatile float y = x;
82 return y;
85 /*********************************************************************
86 * _matherr (CRTDLL.@)
88 int CDECL _matherr(struct _exception *e)
90 return 0;
94 static double math_error(int type, const char *name, double arg1, double arg2, double retval)
96 struct _exception exception = {type, (char *)name, arg1, arg2, retval};
98 TRACE("(%d, %s, %g, %g, %g)\n", type, debugstr_a(name), arg1, arg2, retval);
100 if (MSVCRT_default_matherr_func && MSVCRT_default_matherr_func(&exception))
101 return exception.retval;
103 switch (type)
105 case _DOMAIN:
106 *_errno() = EDOM;
107 break;
108 case _SING:
109 case _OVERFLOW:
110 *_errno() = ERANGE;
111 break;
112 case _UNDERFLOW:
113 /* don't set errno */
114 break;
115 default:
116 ERR("Unhandled math error!\n");
119 return exception.retval;
122 /*********************************************************************
123 * __setusermatherr (MSVCRT.@)
125 void CDECL __setusermatherr(MSVCRT_matherr_func func)
127 MSVCRT_default_matherr_func = func;
128 TRACE("new matherr handler %p\n", func);
131 /*********************************************************************
132 * _set_SSE2_enable (MSVCRT.@)
134 int CDECL _set_SSE2_enable(int flag)
136 sse2_enabled = flag && sse2_supported;
137 return sse2_enabled;
140 #if defined(_WIN64)
141 # if _MSVCR_VER>=140
142 /*********************************************************************
143 * _get_FMA3_enable (UCRTBASE.@)
145 int CDECL _get_FMA3_enable(void)
147 FIXME("() stub\n");
148 return 0;
150 # endif
152 # if _MSVCR_VER>=120
153 /*********************************************************************
154 * _set_FMA3_enable (MSVCR120.@)
156 int CDECL _set_FMA3_enable(int flag)
158 FIXME("(%x) stub\n", flag);
159 return 0;
161 # endif
162 #endif
164 #if !defined(__i386__) || _MSVCR_VER>=120
166 /*********************************************************************
167 * _chgsignf (MSVCRT.@)
169 float CDECL _chgsignf( float num )
171 union { float f; UINT32 i; } u = { num };
172 u.i ^= 0x80000000;
173 return u.f;
176 /*********************************************************************
177 * _copysignf (MSVCRT.@)
179 * Copied from musl: src/math/copysignf.c
181 float CDECL _copysignf( float x, float y )
183 union { float f; UINT32 i; } ux = { x }, uy = { y };
184 ux.i &= 0x7fffffff;
185 ux.i |= uy.i & 0x80000000;
186 return ux.f;
189 /*********************************************************************
190 * _nextafterf (MSVCRT.@)
192 float CDECL _nextafterf( float num, float next )
194 if (!isfinite(num) || !isfinite(next)) *_errno() = EDOM;
195 return unix_funcs->nextafterf( num, next );
198 /*********************************************************************
199 * _logbf (MSVCRT.@)
201 float CDECL _logbf( float num )
203 float ret = unix_funcs->logbf(num);
204 if (isnan(num)) return math_error(_DOMAIN, "_logbf", num, 0, ret);
205 if (!num) return math_error(_SING, "_logbf", num, 0, ret);
206 return ret;
209 #endif
211 #ifndef __i386__
213 /*********************************************************************
214 * _fpclassf (MSVCRT.@)
216 int CDECL _fpclassf( float num )
218 union { float f; UINT32 i; } u = { num };
219 int e = u.i >> 23 & 0xff;
220 int s = u.i >> 31;
222 switch (e)
224 case 0:
225 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
226 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
227 case 0xff:
228 if (u.i << 9) return ((u.i >> 22) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
229 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
230 default:
231 return s ? _FPCLASS_NN : _FPCLASS_PN;
235 /*********************************************************************
236 * _finitef (MSVCRT.@)
238 int CDECL _finitef( float num )
240 union { float f; UINT32 i; } u = { num };
241 return (u.i & 0x7fffffff) < 0x7f800000;
244 /*********************************************************************
245 * _isnanf (MSVCRT.@)
247 int CDECL _isnanf( float num )
249 union { float f; UINT32 i; } u = { num };
250 return (u.i & 0x7fffffff) > 0x7f800000;
253 /*********************************************************************
254 * acosf (MSVCRT.@)
256 * Copied from musl: src/math/acosf.c
258 static float acosf_R(float z)
260 static const float pS0 = 1.6666586697e-01,
261 pS1 = -4.2743422091e-02,
262 pS2 = -8.6563630030e-03,
263 qS1 = -7.0662963390e-01;
265 float p, q;
266 p = z * (pS0 + z * (pS1 + z * pS2));
267 q = 1.0f + z * qS1;
268 return p / q;
271 float CDECL acosf( float x )
273 static const float pio2_hi = 1.5707962513e+00,
274 pio2_lo = 7.5497894159e-08;
276 float z, w, s, c, df;
277 unsigned int hx, ix;
279 hx = *(unsigned int*)&x;
280 ix = hx & 0x7fffffff;
281 /* |x| >= 1 or nan */
282 if (ix >= 0x3f800000) {
283 if (ix == 0x3f800000) {
284 if (hx >> 31)
285 return 2 * pio2_lo + 2 * pio2_hi + 7.5231638453e-37;
286 return 0;
288 if (isnan(x)) return x;
289 return math_error(_DOMAIN, "acosf", x, 0, 0 / (x - x));
291 /* |x| < 0.5 */
292 if (ix < 0x3f000000) {
293 if (ix <= 0x32800000) /* |x| < 2**-26 */
294 return pio2_lo + pio2_hi + 7.5231638453e-37;
295 return pio2_hi - (x - (pio2_lo - x * acosf_R(x * x)));
297 /* x < -0.5 */
298 if (hx >> 31) {
299 z = (1 + x) * 0.5f;
300 s = sqrtf(z);
301 w = acosf_R(z) * s - pio2_lo;
302 return 2 * (pio2_hi - (s + w));
304 /* x > 0.5 */
305 z = (1 - x) * 0.5f;
306 s = sqrtf(z);
307 hx = *(unsigned int*)&s & 0xfffff000;
308 df = *(float*)&hx;
309 c = (z - df * df) / (s + df);
310 w = acosf_R(z) * s + c;
311 return 2 * (df + w);
314 /*********************************************************************
315 * asinf (MSVCRT.@)
317 * Copied from musl: src/math/asinf.c
319 static float asinf_R(float z)
321 /* coefficients for R(x^2) */
322 static const float pS0 = 1.6666586697e-01,
323 pS1 = -4.2743422091e-02,
324 pS2 = -8.6563630030e-03,
325 qS1 = -7.0662963390e-01;
327 float p, q;
328 p = z * (pS0 + z * (pS1 + z * pS2));
329 q = 1.0f + z * qS1;
330 return p / q;
333 float CDECL asinf( float x )
335 static const double pio2 = 1.570796326794896558e+00;
337 double s;
338 float z;
339 unsigned int hx, ix;
341 hx = *(unsigned int*)&x;
342 ix = hx & 0x7fffffff;
343 if (ix >= 0x3f800000) { /* |x| >= 1 */
344 if (ix == 0x3f800000) /* |x| == 1 */
345 return x * pio2 + 7.5231638453e-37; /* asin(+-1) = +-pi/2 with inexact */
346 if (isnan(x)) return x;
347 return math_error(_DOMAIN, "asinf", x, 0, 0 / (x - x));
349 if (ix < 0x3f000000) { /* |x| < 0.5 */
350 /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
351 if (ix < 0x39800000 && ix >= 0x00800000)
352 return x;
353 return x + x * asinf_R(x * x);
355 /* 1 > |x| >= 0.5 */
356 z = (1 - fabsf(x)) * 0.5f;
357 s = sqrt(z);
358 x = pio2 - 2 * (s + s * asinf_R(z));
359 if (hx >> 31)
360 return -x;
361 return x;
364 /*********************************************************************
365 * atanf (MSVCRT.@)
367 * Copied from musl: src/math/atanf.c
369 float CDECL atanf( float x )
371 static const float atanhi[] = {
372 4.6364760399e-01,
373 7.8539812565e-01,
374 9.8279368877e-01,
375 1.5707962513e+00,
377 static const float atanlo[] = {
378 5.0121582440e-09,
379 3.7748947079e-08,
380 3.4473217170e-08,
381 7.5497894159e-08,
383 static const float aT[] = {
384 3.3333328366e-01,
385 -1.9999158382e-01,
386 1.4253635705e-01,
387 -1.0648017377e-01,
388 6.1687607318e-02,
391 float w, s1, s2, z;
392 unsigned int ix, sign;
393 int id;
395 #if _MSVCR_VER == 0
396 if (isnan(x)) return math_error(_DOMAIN, "atanf", x, 0, x);
397 #endif
399 ix = *(unsigned int*)&x;
400 sign = ix >> 31;
401 ix &= 0x7fffffff;
402 if (ix >= 0x4c800000) { /* if |x| >= 2**26 */
403 if (isnan(x))
404 return x;
405 z = atanhi[3] + 7.5231638453e-37;
406 return sign ? -z : z;
408 if (ix < 0x3ee00000) { /* |x| < 0.4375 */
409 if (ix < 0x39800000) { /* |x| < 2**-12 */
410 if (ix < 0x00800000)
411 /* raise underflow for subnormal x */
412 fp_barrierf(x*x);
413 return x;
415 id = -1;
416 } else {
417 x = fabsf(x);
418 if (ix < 0x3f980000) { /* |x| < 1.1875 */
419 if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */
420 id = 0;
421 x = (2.0f * x - 1.0f) / (2.0f + x);
422 } else { /* 11/16 <= |x| < 19/16 */
423 id = 1;
424 x = (x - 1.0f) / (x + 1.0f);
426 } else {
427 if (ix < 0x401c0000) { /* |x| < 2.4375 */
428 id = 2;
429 x = (x - 1.5f) / (1.0f + 1.5f * x);
430 } else { /* 2.4375 <= |x| < 2**26 */
431 id = 3;
432 x = -1.0f / x;
436 /* end of argument reduction */
437 z = x * x;
438 w = z * z;
439 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
440 s1 = z * (aT[0] + w * (aT[2] + w * aT[4]));
441 s2 = w * (aT[1] + w * aT[3]);
442 if (id < 0)
443 return x - x * (s1 + s2);
444 z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x);
445 return sign ? -z : z;
448 /*********************************************************************
449 * atan2f (MSVCRT.@)
451 * Copied from musl: src/math/atan2f.c
453 float CDECL atan2f( float y, float x )
455 static const float pi = 3.1415927410e+00,
456 pi_lo = -8.7422776573e-08;
458 float z;
459 unsigned int m, ix, iy;
461 if (isnan(x) || isnan(y))
462 return x + y;
463 ix = *(unsigned int*)&x;
464 iy = *(unsigned int*)&y;
465 if (ix == 0x3f800000) /* x=1.0 */
466 return atanf(y);
467 m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
468 ix &= 0x7fffffff;
469 iy &= 0x7fffffff;
471 /* when y = 0 */
472 if (iy == 0) {
473 switch (m) {
474 case 0:
475 case 1: return y; /* atan(+-0,+anything)=+-0 */
476 case 2: return pi; /* atan(+0,-anything) = pi */
477 case 3: return -pi; /* atan(-0,-anything) =-pi */
480 /* when x = 0 */
481 if (ix == 0)
482 return m & 1 ? -pi / 2 : pi / 2;
483 /* when x is INF */
484 if (ix == 0x7f800000) {
485 if (iy == 0x7f800000) {
486 switch (m) {
487 case 0: return pi / 4; /* atan(+INF,+INF) */
488 case 1: return -pi / 4; /* atan(-INF,+INF) */
489 case 2: return 3 * pi / 4; /*atan(+INF,-INF)*/
490 case 3: return -3 * pi / 4; /*atan(-INF,-INF)*/
492 } else {
493 switch (m) {
494 case 0: return 0.0f; /* atan(+...,+INF) */
495 case 1: return -0.0f; /* atan(-...,+INF) */
496 case 2: return pi; /* atan(+...,-INF) */
497 case 3: return -pi; /* atan(-...,-INF) */
501 /* |y/x| > 0x1p26 */
502 if (ix + (26 << 23) < iy || iy == 0x7f800000)
503 return m & 1 ? -pi / 2 : pi / 2;
505 /* z = atan(|y/x|) with correct underflow */
506 if ((m & 2) && iy + (26 << 23) < ix) /*|y/x| < 0x1p-26, x < 0 */
507 z = 0.0;
508 else
509 z = atanf(fabsf(y / x));
510 switch (m) {
511 case 0: return z; /* atan(+,+) */
512 case 1: return -z; /* atan(-,+) */
513 case 2: return pi - (z - pi_lo); /* atan(+,-) */
514 default: /* case 3 */
515 return (z - pi_lo) - pi; /* atan(-,-) */
519 /*********************************************************************
520 * cosf (MSVCRT.@)
522 float CDECL cosf( float x )
524 float ret = unix_funcs->cosf( x );
525 if (!isfinite(x)) return math_error(_DOMAIN, "cosf", x, 0, ret);
526 return ret;
529 /*********************************************************************
530 * coshf (MSVCRT.@)
532 float CDECL coshf( float x )
534 float ret = unix_funcs->coshf( x );
535 if (isnan(x)) return math_error(_DOMAIN, "coshf", x, 0, ret);
536 return ret;
539 /*********************************************************************
540 * expf (MSVCRT.@)
542 float CDECL expf( float x )
544 float ret = unix_funcs->expf( x );
545 if (isnan(x)) return math_error(_DOMAIN, "expf", x, 0, ret);
546 if (isfinite(x) && !ret) return math_error(_UNDERFLOW, "expf", x, 0, ret);
547 if (isfinite(x) && !isfinite(ret)) return math_error(_OVERFLOW, "expf", x, 0, ret);
548 return ret;
551 /*********************************************************************
552 * fmodf (MSVCRT.@)
554 float CDECL fmodf( float x, float y )
556 float ret = unix_funcs->fmodf( x, y );
557 if (!isfinite(x) || !isfinite(y)) return math_error(_DOMAIN, "fmodf", x, 0, ret);
558 return ret;
561 /*********************************************************************
562 * logf (MSVCRT.@)
564 float CDECL logf( float x )
566 float ret = unix_funcs->logf( x );
567 if (x < 0.0) return math_error(_DOMAIN, "logf", x, 0, ret);
568 if (x == 0.0) return math_error(_SING, "logf", x, 0, ret);
569 return ret;
572 /*********************************************************************
573 * log10f (MSVCRT.@)
575 float CDECL log10f( float x )
577 float ret = unix_funcs->log10f( x );
578 if (x < 0.0) return math_error(_DOMAIN, "log10f", x, 0, ret);
579 if (x == 0.0) return math_error(_SING, "log10f", x, 0, ret);
580 return ret;
583 /*********************************************************************
584 * powf (MSVCRT.@)
586 float CDECL powf( float x, float y )
588 float z = unix_funcs->powf(x,y);
589 if (x < 0 && y != floorf(y)) return math_error(_DOMAIN, "powf", x, y, z);
590 if (!x && isfinite(y) && y < 0) return math_error(_SING, "powf", x, y, z);
591 if (isfinite(x) && isfinite(y) && !isfinite(z)) return math_error(_OVERFLOW, "powf", x, y, z);
592 if (x && isfinite(x) && isfinite(y) && !z) return math_error(_UNDERFLOW, "powf", x, y, z);
593 return z;
596 /*********************************************************************
597 * sinf (MSVCRT.@)
599 float CDECL sinf( float x )
601 float ret = unix_funcs->sinf( x );
602 if (!isfinite(x)) return math_error(_DOMAIN, "sinf", x, 0, ret);
603 return ret;
606 /*********************************************************************
607 * sinhf (MSVCRT.@)
609 float CDECL sinhf( float x )
611 float ret = unix_funcs->sinhf( x );
612 if (isnan(x)) return math_error(_DOMAIN, "sinhf", x, 0, ret);
613 return ret;
616 /*********************************************************************
617 * sqrtf (MSVCRT.@)
619 * Copied from musl: src/math/sqrtf.c
621 float CDECL sqrtf( float x )
623 static const float tiny = 1.0e-30;
625 float z;
626 int sign = 0x80000000;
627 int ix,s,q,m,t,i;
628 unsigned int r;
630 ix = *(int*)&x;
632 /* take care of Inf and NaN */
633 if ((ix & 0x7f800000) == 0x7f800000 && (ix == 0x7f800000 || ix & 0x7fffff))
634 return x;
636 /* take care of zero */
637 if (ix <= 0) {
638 if ((ix & ~sign) == 0)
639 return x; /* sqrt(+-0) = +-0 */
640 return math_error(_DOMAIN, "sqrtf", x, 0, (x - x) / (x - x)); /* sqrt(-ve) = sNaN */
642 /* normalize x */
643 m = ix >> 23;
644 if (m == 0) { /* subnormal x */
645 for (i = 0; (ix & 0x00800000) == 0; i++)
646 ix <<= 1;
647 m -= i - 1;
649 m -= 127; /* unbias exponent */
650 ix = (ix & 0x007fffff) | 0x00800000;
651 if (m & 1) /* odd m, double x to make it even */
652 ix += ix;
653 m >>= 1; /* m = [m/2] */
655 /* generate sqrt(x) bit by bit */
656 ix += ix;
657 q = s = 0; /* q = sqrt(x) */
658 r = 0x01000000; /* r = moving bit from right to left */
660 while (r != 0) {
661 t = s + r;
662 if (t <= ix) {
663 s = t + r;
664 ix -= t;
665 q += r;
667 ix += ix;
668 r >>= 1;
671 /* use floating add to find out rounding direction */
672 if (ix != 0) {
673 z = 1.0f - tiny; /* raise inexact flag */
674 if (z >= 1.0f) {
675 z = 1.0f + tiny;
676 if (z > 1.0f)
677 q += 2;
678 else
679 q += q & 1;
682 ix = (q >> 1) + 0x3f000000;
683 r = ix + ((unsigned int)m << 23);
684 z = *(float*)&r;
685 return z;
688 /*********************************************************************
689 * tanf (MSVCRT.@)
691 float CDECL tanf( float x )
693 float ret = unix_funcs->tanf(x);
694 if (!isfinite(x)) return math_error(_DOMAIN, "tanf", x, 0, ret);
695 return ret;
698 /*********************************************************************
699 * tanhf (MSVCRT.@)
701 float CDECL tanhf( float x )
703 float ret = unix_funcs->tanhf(x);
704 if (!isfinite(x)) return math_error(_DOMAIN, "tanhf", x, 0, ret);
705 return ret;
708 /*********************************************************************
709 * ceilf (MSVCRT.@)
711 float CDECL ceilf( float x )
713 return unix_funcs->ceilf(x);
716 /*********************************************************************
717 * fabsf (MSVCRT.@)
719 * Copied from musl: src/math/fabsf.c
721 float CDECL fabsf( float x )
723 union { float f; UINT32 i; } u = { x };
724 u.i &= 0x7fffffff;
725 return u.f;
728 /*********************************************************************
729 * floorf (MSVCRT.@)
731 float CDECL floorf( float x )
733 return unix_funcs->floorf(x);
736 /*********************************************************************
737 * frexpf (MSVCRT.@)
739 float CDECL frexpf( float x, int *exp )
741 return unix_funcs->frexpf( x, exp );
744 /*********************************************************************
745 * modff (MSVCRT.@)
747 float CDECL modff( float x, float *iptr )
749 return unix_funcs->modff( x, iptr );
752 #endif
754 /*********************************************************************
755 * acos (MSVCRT.@)
757 * Copied from musl: src/math/acos.c
759 static double acos_R(double z)
761 static const double pS0 = 1.66666666666666657415e-01,
762 pS1 = -3.25565818622400915405e-01,
763 pS2 = 2.01212532134862925881e-01,
764 pS3 = -4.00555345006794114027e-02,
765 pS4 = 7.91534994289814532176e-04,
766 pS5 = 3.47933107596021167570e-05,
767 qS1 = -2.40339491173441421878e+00,
768 qS2 = 2.02094576023350569471e+00,
769 qS3 = -6.88283971605453293030e-01,
770 qS4 = 7.70381505559019352791e-02;
772 double p, q;
773 p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
774 q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
775 return p/q;
778 double CDECL acos( double x )
780 static const double pio2_hi = 1.57079632679489655800e+00,
781 pio2_lo = 6.12323399573676603587e-17;
783 double z, w, s, c, df;
784 unsigned int hx, ix;
785 ULONGLONG llx;
787 hx = *(ULONGLONG*)&x >> 32;
788 ix = hx & 0x7fffffff;
789 /* |x| >= 1 or nan */
790 if (ix >= 0x3ff00000) {
791 unsigned int lx;
793 lx = *(ULONGLONG*)&x;
794 if (((ix - 0x3ff00000) | lx) == 0) {
795 /* acos(1)=0, acos(-1)=pi */
796 if (hx >> 31)
797 return 2 * pio2_hi + 7.5231638452626401e-37;
798 return 0;
800 if (isnan(x)) return x;
801 return math_error(_DOMAIN, "acos", x, 0, 0 / (x - x));
803 /* |x| < 0.5 */
804 if (ix < 0x3fe00000) {
805 if (ix <= 0x3c600000) /* |x| < 2**-57 */
806 return pio2_hi + 7.5231638452626401e-37;
807 return pio2_hi - (x - (pio2_lo - x * acos_R(x * x)));
809 /* x < -0.5 */
810 if (hx >> 31) {
811 z = (1.0 + x) * 0.5;
812 s = sqrt(z);
813 w = acos_R(z) * s - pio2_lo;
814 return 2 * (pio2_hi - (s + w));
816 /* x > 0.5 */
817 z = (1.0 - x) * 0.5;
818 s = sqrt(z);
819 df = s;
820 llx = (*(ULONGLONG*)&df >> 32) << 32;
821 df = *(double*)&llx;
822 c = (z - df * df) / (s + df);
823 w = acos_R(z) * s + c;
824 return 2 * (df + w);
827 /*********************************************************************
828 * asin (MSVCRT.@)
830 * Copied from musl: src/math/asin.c
832 static double asin_R(double z)
834 /* coefficients for R(x^2) */
835 static const double pS0 = 1.66666666666666657415e-01,
836 pS1 = -3.25565818622400915405e-01,
837 pS2 = 2.01212532134862925881e-01,
838 pS3 = -4.00555345006794114027e-02,
839 pS4 = 7.91534994289814532176e-04,
840 pS5 = 3.47933107596021167570e-05,
841 qS1 = -2.40339491173441421878e+00,
842 qS2 = 2.02094576023350569471e+00,
843 qS3 = -6.88283971605453293030e-01,
844 qS4 = 7.70381505559019352791e-02;
846 double p, q;
847 p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
848 q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
849 return p / q;
852 double CDECL asin( double x )
854 static const double pio2_hi = 1.57079632679489655800e+00,
855 pio2_lo = 6.12323399573676603587e-17;
857 double z, r, s;
858 unsigned int hx, ix;
859 ULONGLONG llx;
861 hx = *(ULONGLONG*)&x >> 32;
862 ix = hx & 0x7fffffff;
863 /* |x| >= 1 or nan */
864 if (ix >= 0x3ff00000) {
865 unsigned int lx;
866 lx = *(ULONGLONG*)&x;
867 if (((ix - 0x3ff00000) | lx) == 0)
868 /* asin(1) = +-pi/2 with inexact */
869 return x * pio2_hi + 7.5231638452626401e-37;
870 if (isnan(x)) return x;
871 return math_error(_DOMAIN, "asin", x, 0, 0 / (x - x));
873 /* |x| < 0.5 */
874 if (ix < 0x3fe00000) {
875 /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
876 if (ix < 0x3e500000 && ix >= 0x00100000)
877 return x;
878 return x + x * asin_R(x * x);
880 /* 1 > |x| >= 0.5 */
881 z = (1 - fabs(x)) * 0.5;
882 s = sqrt(z);
883 r = asin_R(z);
884 if (ix >= 0x3fef3333) { /* if |x| > 0.975 */
885 x = pio2_hi - (2 * (s + s * r) - pio2_lo);
886 } else {
887 double f, c;
888 /* f+c = sqrt(z) */
889 f = s;
890 llx = (*(ULONGLONG*)&f >> 32) << 32;
891 f = *(double*)&llx;
892 c = (z - f * f) / (s + f);
893 x = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * f));
895 if (hx >> 31)
896 return -x;
897 return x;
900 /*********************************************************************
901 * atan (MSVCRT.@)
903 * Copied from musl: src/math/atan.c
905 double CDECL atan( double x )
907 static const double atanhi[] = {
908 4.63647609000806093515e-01,
909 7.85398163397448278999e-01,
910 9.82793723247329054082e-01,
911 1.57079632679489655800e+00,
913 static const double atanlo[] = {
914 2.26987774529616870924e-17,
915 3.06161699786838301793e-17,
916 1.39033110312309984516e-17,
917 6.12323399573676603587e-17,
919 static const double aT[] = {
920 3.33333333333329318027e-01,
921 -1.99999999998764832476e-01,
922 1.42857142725034663711e-01,
923 -1.11111104054623557880e-01,
924 9.09088713343650656196e-02,
925 -7.69187620504482999495e-02,
926 6.66107313738753120669e-02,
927 -5.83357013379057348645e-02,
928 4.97687799461593236017e-02,
929 -3.65315727442169155270e-02,
930 1.62858201153657823623e-02,
933 double w, s1, s2, z;
934 unsigned int ix, sign;
935 int id;
937 #if _MSVCR_VER == 0
938 if (isnan(x)) return math_error(_DOMAIN, "atan", x, 0, x);
939 #endif
941 ix = *(ULONGLONG*)&x >> 32;
942 sign = ix >> 31;
943 ix &= 0x7fffffff;
944 if (ix >= 0x44100000) { /* if |x| >= 2^66 */
945 if (isnan(x))
946 return x;
947 z = atanhi[3] + 7.5231638452626401e-37;
948 return sign ? -z : z;
950 if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
951 if (ix < 0x3e400000) { /* |x| < 2^-27 */
952 if (ix < 0x00100000)
953 /* raise underflow for subnormal x */
954 fp_barrierf((float)x);
955 return x;
957 id = -1;
958 } else {
959 x = fabs(x);
960 if (ix < 0x3ff30000) { /* |x| < 1.1875 */
961 if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */
962 id = 0;
963 x = (2.0 * x - 1.0) / (2.0 + x);
964 } else { /* 11/16 <= |x| < 19/16 */
965 id = 1;
966 x = (x - 1.0) / (x + 1.0);
968 } else {
969 if (ix < 0x40038000) { /* |x| < 2.4375 */
970 id = 2;
971 x = (x - 1.5) / (1.0 + 1.5 * x);
972 } else { /* 2.4375 <= |x| < 2^66 */
973 id = 3;
974 x = -1.0 / x;
978 /* end of argument reduction */
979 z = x * x;
980 w = z * z;
981 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
982 s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10])))));
983 s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
984 if (id < 0)
985 return x - x * (s1 + s2);
986 z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x);
987 return sign ? -z : z;
990 /*********************************************************************
991 * atan2 (MSVCRT.@)
993 * Copied from musl: src/math/atan2.c
995 double CDECL atan2( double y, double x )
997 static const double pi = 3.1415926535897931160E+00,
998 pi_lo = 1.2246467991473531772E-16;
1000 double z;
1001 unsigned int m, lx, ly, ix, iy;
1003 if (isnan(x) || isnan(y))
1004 return x+y;
1005 ix = *(ULONGLONG*)&x >> 32;
1006 lx = *(ULONGLONG*)&x;
1007 iy = *(ULONGLONG*)&y >> 32;
1008 ly = *(ULONGLONG*)&y;
1009 if (((ix - 0x3ff00000) | lx) == 0) /* x = 1.0 */
1010 return atan(y);
1011 m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */
1012 ix = ix & 0x7fffffff;
1013 iy = iy & 0x7fffffff;
1015 /* when y = 0 */
1016 if ((iy | ly) == 0) {
1017 switch(m) {
1018 case 0:
1019 case 1: return y; /* atan(+-0,+anything)=+-0 */
1020 case 2: return pi; /* atan(+0,-anything) = pi */
1021 case 3: return -pi; /* atan(-0,-anything) =-pi */
1024 /* when x = 0 */
1025 if ((ix | lx) == 0)
1026 return m & 1 ? -pi / 2 : pi / 2;
1027 /* when x is INF */
1028 if (ix == 0x7ff00000) {
1029 if (iy == 0x7ff00000) {
1030 switch(m) {
1031 case 0: return pi / 4; /* atan(+INF,+INF) */
1032 case 1: return -pi / 4; /* atan(-INF,+INF) */
1033 case 2: return 3 * pi / 4; /* atan(+INF,-INF) */
1034 case 3: return -3 * pi / 4; /* atan(-INF,-INF) */
1036 } else {
1037 switch(m) {
1038 case 0: return 0.0; /* atan(+...,+INF) */
1039 case 1: return -0.0; /* atan(-...,+INF) */
1040 case 2: return pi; /* atan(+...,-INF) */
1041 case 3: return -pi; /* atan(-...,-INF) */
1045 /* |y/x| > 0x1p64 */
1046 if (ix + (64 << 20) < iy || iy == 0x7ff00000)
1047 return m & 1 ? -pi / 2 : pi / 2;
1049 /* z = atan(|y/x|) without spurious underflow */
1050 if ((m & 2) && iy + (64 << 20) < ix) /* |y/x| < 0x1p-64, x<0 */
1051 z = 0;
1052 else
1053 z = atan(fabs(y / x));
1054 switch (m) {
1055 case 0: return z; /* atan(+,+) */
1056 case 1: return -z; /* atan(-,+) */
1057 case 2: return pi - (z - pi_lo); /* atan(+,-) */
1058 default: /* case 3 */
1059 return (z - pi_lo) - pi; /* atan(-,-) */
1063 /*********************************************************************
1064 * cos (MSVCRT.@)
1066 double CDECL cos( double x )
1068 double ret = unix_funcs->cos( x );
1069 if (!isfinite(x)) return math_error(_DOMAIN, "cos", x, 0, ret);
1070 return ret;
1073 /*********************************************************************
1074 * cosh (MSVCRT.@)
1076 double CDECL cosh( double x )
1078 double ret = unix_funcs->cosh( x );
1079 if (isnan(x)) return math_error(_DOMAIN, "cosh", x, 0, ret);
1080 return ret;
1083 /*********************************************************************
1084 * exp (MSVCRT.@)
1086 double CDECL exp( double x )
1088 double ret = unix_funcs->exp( x );
1089 if (isnan(x)) return math_error(_DOMAIN, "exp", x, 0, ret);
1090 if (isfinite(x) && !ret) return math_error(_UNDERFLOW, "exp", x, 0, ret);
1091 if (isfinite(x) && !isfinite(ret)) return math_error(_OVERFLOW, "exp", x, 0, ret);
1092 return ret;
1095 /*********************************************************************
1096 * fmod (MSVCRT.@)
1098 double CDECL fmod( double x, double y )
1100 double ret = unix_funcs->fmod( x, y );
1101 if (!isfinite(x) || !isfinite(y)) return math_error(_DOMAIN, "fmod", x, y, ret);
1102 return ret;
1105 /*********************************************************************
1106 * log (MSVCRT.@)
1108 double CDECL log( double x )
1110 double ret = unix_funcs->log( x );
1111 if (x < 0.0) return math_error(_DOMAIN, "log", x, 0, ret);
1112 if (x == 0.0) return math_error(_SING, "log", x, 0, ret);
1113 return ret;
1116 /*********************************************************************
1117 * log10 (MSVCRT.@)
1119 double CDECL log10( double x )
1121 double ret = unix_funcs->log10( x );
1122 if (x < 0.0) return math_error(_DOMAIN, "log10", x, 0, ret);
1123 if (x == 0.0) return math_error(_SING, "log10", x, 0, ret);
1124 return ret;
1127 /*********************************************************************
1128 * pow (MSVCRT.@)
1130 double CDECL pow( double x, double y )
1132 double z = unix_funcs->pow(x,y);
1133 if (x < 0 && y != floor(y))
1134 return math_error(_DOMAIN, "pow", x, y, z);
1135 if (!x && isfinite(y) && y < 0)
1136 return math_error(_SING, "pow", x, y, z);
1137 if (isfinite(x) && isfinite(y) && !isfinite(z))
1138 return math_error(_OVERFLOW, "pow", x, y, z);
1139 if (x && isfinite(x) && isfinite(y) && !z)
1140 return math_error(_UNDERFLOW, "pow", x, y, z);
1141 return z;
1144 /*********************************************************************
1145 * sin (MSVCRT.@)
1147 double CDECL sin( double x )
1149 double ret = unix_funcs->sin( x );
1150 if (!isfinite(x)) return math_error(_DOMAIN, "sin", x, 0, ret);
1151 return ret;
1154 /*********************************************************************
1155 * sinh (MSVCRT.@)
1157 double CDECL sinh( double x )
1159 double ret = unix_funcs->sinh( x );
1160 if (isnan(x)) return math_error(_DOMAIN, "sinh", x, 0, ret);
1161 return ret;
1164 /*********************************************************************
1165 * sqrt (MSVCRT.@)
1167 * Copied from musl: src/math/sqrt.c
1169 double CDECL sqrt( double x )
1171 static const double tiny = 1.0e-300;
1173 double z;
1174 int sign = 0x80000000;
1175 int ix0,s0,q,m,t,i;
1176 unsigned int r,t1,s1,ix1,q1;
1177 ULONGLONG ix;
1179 ix = *(ULONGLONG*)&x;
1180 ix0 = ix >> 32;
1181 ix1 = ix;
1183 /* take care of Inf and NaN */
1184 if (isnan(x) || (isinf(x) && x > 0))
1185 return x;
1187 /* take care of zero */
1188 if (ix0 <= 0) {
1189 if (((ix0 & ~sign) | ix1) == 0)
1190 return x; /* sqrt(+-0) = +-0 */
1191 if (ix0 < 0)
1192 return math_error(_DOMAIN, "sqrt", x, 0, (x - x) / (x - x));
1194 /* normalize x */
1195 m = ix0 >> 20;
1196 if (m == 0) { /* subnormal x */
1197 while (ix0 == 0) {
1198 m -= 21;
1199 ix0 |= (ix1 >> 11);
1200 ix1 <<= 21;
1202 for (i=0; (ix0 & 0x00100000) == 0; i++)
1203 ix0 <<= 1;
1204 m -= i - 1;
1205 ix0 |= ix1 >> (32 - i);
1206 ix1 <<= i;
1208 m -= 1023; /* unbias exponent */
1209 ix0 = (ix0 & 0x000fffff) | 0x00100000;
1210 if (m & 1) { /* odd m, double x to make it even */
1211 ix0 += ix0 + ((ix1 & sign) >> 31);
1212 ix1 += ix1;
1214 m >>= 1; /* m = [m/2] */
1216 /* generate sqrt(x) bit by bit */
1217 ix0 += ix0 + ((ix1 & sign) >> 31);
1218 ix1 += ix1;
1219 q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
1220 r = 0x00200000; /* r = moving bit from right to left */
1222 while (r != 0) {
1223 t = s0 + r;
1224 if (t <= ix0) {
1225 s0 = t + r;
1226 ix0 -= t;
1227 q += r;
1229 ix0 += ix0 + ((ix1 & sign) >> 31);
1230 ix1 += ix1;
1231 r >>= 1;
1234 r = sign;
1235 while (r != 0) {
1236 t1 = s1 + r;
1237 t = s0;
1238 if (t < ix0 || (t == ix0 && t1 <= ix1)) {
1239 s1 = t1 + r;
1240 if ((t1&sign) == sign && (s1 & sign) == 0)
1241 s0++;
1242 ix0 -= t;
1243 if (ix1 < t1)
1244 ix0--;
1245 ix1 -= t1;
1246 q1 += r;
1248 ix0 += ix0 + ((ix1 & sign) >> 31);
1249 ix1 += ix1;
1250 r >>= 1;
1253 /* use floating add to find out rounding direction */
1254 if ((ix0 | ix1) != 0) {
1255 z = 1.0 - tiny; /* raise inexact flag */
1256 if (z >= 1.0) {
1257 z = 1.0 + tiny;
1258 if (q1 == (unsigned int)0xffffffff) {
1259 q1 = 0;
1260 q++;
1261 } else if (z > 1.0) {
1262 if (q1 == (unsigned int)0xfffffffe)
1263 q++;
1264 q1 += 2;
1265 } else
1266 q1 += q1 & 1;
1269 ix0 = (q >> 1) + 0x3fe00000;
1270 ix1 = q1 >> 1;
1271 if (q & 1)
1272 ix1 |= sign;
1273 ix = ix0 + ((unsigned int)m << 20);
1274 ix <<= 32;
1275 ix |= ix1;
1276 return *(double*)&ix;
1279 /*********************************************************************
1280 * tan (MSVCRT.@)
1282 double CDECL tan( double x )
1284 double ret = unix_funcs->tan(x);
1285 if (!isfinite(x)) return math_error(_DOMAIN, "tan", x, 0, ret);
1286 return ret;
1289 /*********************************************************************
1290 * tanh (MSVCRT.@)
1292 double CDECL tanh( double x )
1294 double ret = unix_funcs->tanh(x);
1295 if (isnan(x)) return math_error(_DOMAIN, "tanh", x, 0, ret);
1296 return ret;
1300 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
1302 #define CREATE_FPU_FUNC1(name, call) \
1303 __ASM_GLOBAL_FUNC(name, \
1304 "pushl %ebp\n\t" \
1305 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1306 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1307 "movl %esp, %ebp\n\t" \
1308 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1309 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1310 "fstpl (%esp)\n\t" /* store function argument */ \
1311 "fwait\n\t" \
1312 "movl $1, %ecx\n\t" /* empty FPU stack */ \
1313 "1:\n\t" \
1314 "fxam\n\t" \
1315 "fstsw %ax\n\t" \
1316 "and $0x4500, %ax\n\t" \
1317 "cmp $0x4100, %ax\n\t" \
1318 "je 2f\n\t" \
1319 "fstpl (%esp,%ecx,8)\n\t" \
1320 "fwait\n\t" \
1321 "incl %ecx\n\t" \
1322 "jmp 1b\n\t" \
1323 "2:\n\t" \
1324 "movl %ecx, -4(%ebp)\n\t" \
1325 "call " __ASM_NAME( #call ) "\n\t" \
1326 "movl -4(%ebp), %ecx\n\t" \
1327 "fstpl (%esp)\n\t" /* save result */ \
1328 "3:\n\t" /* restore FPU stack */ \
1329 "decl %ecx\n\t" \
1330 "fldl (%esp,%ecx,8)\n\t" \
1331 "cmpl $0, %ecx\n\t" \
1332 "jne 3b\n\t" \
1333 "leave\n\t" \
1334 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1335 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1336 "ret")
1338 #define CREATE_FPU_FUNC2(name, call) \
1339 __ASM_GLOBAL_FUNC(name, \
1340 "pushl %ebp\n\t" \
1341 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1342 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1343 "movl %esp, %ebp\n\t" \
1344 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1345 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1346 "fstpl 8(%esp)\n\t" /* store function argument */ \
1347 "fwait\n\t" \
1348 "fstpl (%esp)\n\t" \
1349 "fwait\n\t" \
1350 "movl $2, %ecx\n\t" /* empty FPU stack */ \
1351 "1:\n\t" \
1352 "fxam\n\t" \
1353 "fstsw %ax\n\t" \
1354 "and $0x4500, %ax\n\t" \
1355 "cmp $0x4100, %ax\n\t" \
1356 "je 2f\n\t" \
1357 "fstpl (%esp,%ecx,8)\n\t" \
1358 "fwait\n\t" \
1359 "incl %ecx\n\t" \
1360 "jmp 1b\n\t" \
1361 "2:\n\t" \
1362 "movl %ecx, -4(%ebp)\n\t" \
1363 "call " __ASM_NAME( #call ) "\n\t" \
1364 "movl -4(%ebp), %ecx\n\t" \
1365 "fstpl 8(%esp)\n\t" /* save result */ \
1366 "3:\n\t" /* restore FPU stack */ \
1367 "decl %ecx\n\t" \
1368 "fldl (%esp,%ecx,8)\n\t" \
1369 "cmpl $1, %ecx\n\t" \
1370 "jne 3b\n\t" \
1371 "leave\n\t" \
1372 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1373 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1374 "ret")
1376 CREATE_FPU_FUNC1(_CIacos, acos)
1377 CREATE_FPU_FUNC1(_CIasin, asin)
1378 CREATE_FPU_FUNC1(_CIatan, atan)
1379 CREATE_FPU_FUNC2(_CIatan2, atan2)
1380 CREATE_FPU_FUNC1(_CIcos, cos)
1381 CREATE_FPU_FUNC1(_CIcosh, cosh)
1382 CREATE_FPU_FUNC1(_CIexp, exp)
1383 CREATE_FPU_FUNC2(_CIfmod, fmod)
1384 CREATE_FPU_FUNC1(_CIlog, log)
1385 CREATE_FPU_FUNC1(_CIlog10, log10)
1386 CREATE_FPU_FUNC2(_CIpow, pow)
1387 CREATE_FPU_FUNC1(_CIsin, sin)
1388 CREATE_FPU_FUNC1(_CIsinh, sinh)
1389 CREATE_FPU_FUNC1(_CIsqrt, sqrt)
1390 CREATE_FPU_FUNC1(_CItan, tan)
1391 CREATE_FPU_FUNC1(_CItanh, tanh)
1393 __ASM_GLOBAL_FUNC(_ftol,
1394 "pushl %ebp\n\t"
1395 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1396 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1397 "movl %esp, %ebp\n\t"
1398 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1399 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
1400 "fnstcw (%esp)\n\t"
1401 "mov (%esp), %ax\n\t"
1402 "or $0xc00, %ax\n\t"
1403 "mov %ax, 2(%esp)\n\t"
1404 "fldcw 2(%esp)\n\t"
1405 "fistpq 4(%esp)\n\t"
1406 "fldcw (%esp)\n\t"
1407 "movl 4(%esp), %eax\n\t"
1408 "movl 8(%esp), %edx\n\t"
1409 "leave\n\t"
1410 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1411 __ASM_CFI(".cfi_same_value %ebp\n\t")
1412 "ret")
1414 #endif /* (defined(__GNUC__) || defined(__clang__)) && defined(__i386__) */
1416 /*********************************************************************
1417 * _fpclass (MSVCRT.@)
1419 int CDECL _fpclass(double num)
1421 union { double f; UINT64 i; } u = { num };
1422 int e = u.i >> 52 & 0x7ff;
1423 int s = u.i >> 63;
1425 switch (e)
1427 case 0:
1428 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
1429 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
1430 case 0x7ff:
1431 if (u.i << 12) return ((u.i >> 51) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
1432 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
1433 default:
1434 return s ? _FPCLASS_NN : _FPCLASS_PN;
1438 /*********************************************************************
1439 * _rotl (MSVCRT.@)
1441 unsigned int CDECL MSVCRT__rotl(unsigned int num, int shift)
1443 shift &= 31;
1444 return (num << shift) | (num >> (32-shift));
1447 /*********************************************************************
1448 * _lrotl (MSVCRT.@)
1450 __msvcrt_ulong CDECL MSVCRT__lrotl(__msvcrt_ulong num, int shift)
1452 shift &= 0x1f;
1453 return (num << shift) | (num >> (32-shift));
1456 /*********************************************************************
1457 * _lrotr (MSVCRT.@)
1459 __msvcrt_ulong CDECL MSVCRT__lrotr(__msvcrt_ulong num, int shift)
1461 shift &= 0x1f;
1462 return (num >> shift) | (num << (32-shift));
1465 /*********************************************************************
1466 * _rotr (MSVCRT.@)
1468 unsigned int CDECL MSVCRT__rotr(unsigned int num, int shift)
1470 shift &= 0x1f;
1471 return (num >> shift) | (num << (32-shift));
1474 /*********************************************************************
1475 * _rotl64 (MSVCRT.@)
1477 unsigned __int64 CDECL MSVCRT__rotl64(unsigned __int64 num, int shift)
1479 shift &= 63;
1480 return (num << shift) | (num >> (64-shift));
1483 /*********************************************************************
1484 * _rotr64 (MSVCRT.@)
1486 unsigned __int64 CDECL MSVCRT__rotr64(unsigned __int64 num, int shift)
1488 shift &= 63;
1489 return (num >> shift) | (num << (64-shift));
1492 /*********************************************************************
1493 * abs (MSVCRT.@)
1495 int CDECL abs( int n )
1497 return n >= 0 ? n : -n;
1500 /*********************************************************************
1501 * labs (MSVCRT.@)
1503 __msvcrt_long CDECL labs( __msvcrt_long n )
1505 return n >= 0 ? n : -n;
1508 #if _MSVCR_VER>=100
1509 /*********************************************************************
1510 * llabs (MSVCR100.@)
1512 __int64 CDECL llabs( __int64 n )
1514 return n >= 0 ? n : -n;
1516 #endif
1518 #if _MSVCR_VER>=120
1519 /*********************************************************************
1520 * imaxabs (MSVCR120.@)
1522 intmax_t CDECL imaxabs( intmax_t n )
1524 return n >= 0 ? n : -n;
1526 #endif
1528 /*********************************************************************
1529 * _abs64 (MSVCRT.@)
1531 __int64 CDECL _abs64( __int64 n )
1533 return n >= 0 ? n : -n;
1536 /*********************************************************************
1537 * _logb (MSVCRT.@)
1539 double CDECL _logb(double num)
1541 double ret = unix_funcs->logb(num);
1542 if (isnan(num)) return math_error(_DOMAIN, "_logb", num, 0, ret);
1543 if (!num) return math_error(_SING, "_logb", num, 0, ret);
1544 return ret;
1547 /*********************************************************************
1548 * _hypot (MSVCRT.@)
1550 double CDECL _hypot(double x, double y)
1552 /* FIXME: errno handling */
1553 return unix_funcs->hypot( x, y );
1556 /*********************************************************************
1557 * _hypotf (MSVCRT.@)
1559 float CDECL _hypotf(float x, float y)
1561 /* FIXME: errno handling */
1562 return unix_funcs->hypotf( x, y );
1565 /*********************************************************************
1566 * ceil (MSVCRT.@)
1568 double CDECL ceil( double x )
1570 return unix_funcs->ceil(x);
1573 /*********************************************************************
1574 * floor (MSVCRT.@)
1576 double CDECL floor( double x )
1578 return unix_funcs->floor(x);
1581 /*********************************************************************
1582 * fma (MSVCRT.@)
1584 double CDECL fma( double x, double y, double z )
1586 double w = unix_funcs->fma(x, y, z);
1587 if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *_errno() = EDOM;
1588 else if (isinf(x) && isinf(z) && x != z) *_errno() = EDOM;
1589 else if (isinf(y) && isinf(z) && y != z) *_errno() = EDOM;
1590 return w;
1593 /*********************************************************************
1594 * fmaf (MSVCRT.@)
1596 float CDECL fmaf( float x, float y, float z )
1598 float w = unix_funcs->fmaf(x, y, z);
1599 if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *_errno() = EDOM;
1600 else if (isinf(x) && isinf(z) && x != z) *_errno() = EDOM;
1601 else if (isinf(y) && isinf(z) && y != z) *_errno() = EDOM;
1602 return w;
1605 /*********************************************************************
1606 * fabs (MSVCRT.@)
1608 * Copied from musl: src/math/fabsf.c
1610 double CDECL fabs( double x )
1612 union { double f; UINT64 i; } u = { x };
1613 u.i &= ~0ull >> 1;
1614 return u.f;
1617 /*********************************************************************
1618 * frexp (MSVCRT.@)
1620 double CDECL frexp( double x, int *exp )
1622 return unix_funcs->frexp( x, exp );
1625 /*********************************************************************
1626 * modf (MSVCRT.@)
1628 double CDECL modf( double x, double *iptr )
1630 return unix_funcs->modf( x, iptr );
1633 /**********************************************************************
1634 * _statusfp2 (MSVCRT.@)
1636 * Not exported by native msvcrt, added in msvcr80.
1638 #if defined(__i386__) || defined(__x86_64__)
1639 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
1641 #if defined(__GNUC__) || defined(__clang__)
1642 unsigned int flags;
1643 unsigned long fpword;
1645 if (x86_sw)
1647 __asm__ __volatile__( "fstsw %0" : "=m" (fpword) );
1648 flags = 0;
1649 if (fpword & 0x1) flags |= _SW_INVALID;
1650 if (fpword & 0x2) flags |= _SW_DENORMAL;
1651 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1652 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1653 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1654 if (fpword & 0x20) flags |= _SW_INEXACT;
1655 *x86_sw = flags;
1658 if (!sse2_sw) return;
1660 if (sse2_supported)
1662 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1663 flags = 0;
1664 if (fpword & 0x1) flags |= _SW_INVALID;
1665 if (fpword & 0x2) flags |= _SW_DENORMAL;
1666 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1667 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1668 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1669 if (fpword & 0x20) flags |= _SW_INEXACT;
1670 *sse2_sw = flags;
1672 else *sse2_sw = 0;
1673 #else
1674 FIXME( "not implemented\n" );
1675 #endif
1677 #endif
1679 /**********************************************************************
1680 * _statusfp (MSVCRT.@)
1682 unsigned int CDECL _statusfp(void)
1684 unsigned int flags = 0;
1685 #if defined(__i386__) || defined(__x86_64__)
1686 unsigned int x86_sw, sse2_sw;
1688 _statusfp2( &x86_sw, &sse2_sw );
1689 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1690 flags = x86_sw | sse2_sw;
1691 #elif defined(__aarch64__)
1692 ULONG_PTR fpsr;
1694 __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
1695 if (fpsr & 0x1) flags |= _SW_INVALID;
1696 if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
1697 if (fpsr & 0x4) flags |= _SW_OVERFLOW;
1698 if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
1699 if (fpsr & 0x10) flags |= _SW_INEXACT;
1700 if (fpsr & 0x80) flags |= _SW_DENORMAL;
1701 #else
1702 FIXME( "not implemented\n" );
1703 #endif
1704 return flags;
1707 /*********************************************************************
1708 * _clearfp (MSVCRT.@)
1710 unsigned int CDECL _clearfp(void)
1712 unsigned int flags = 0;
1713 #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
1714 unsigned long fpword;
1716 __asm__ __volatile__( "fnstsw %0; fnclex" : "=m" (fpword) );
1717 if (fpword & 0x1) flags |= _SW_INVALID;
1718 if (fpword & 0x2) flags |= _SW_DENORMAL;
1719 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1720 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1721 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1722 if (fpword & 0x20) flags |= _SW_INEXACT;
1724 if (sse2_supported)
1726 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1727 if (fpword & 0x1) flags |= _SW_INVALID;
1728 if (fpword & 0x2) flags |= _SW_DENORMAL;
1729 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
1730 if (fpword & 0x8) flags |= _SW_OVERFLOW;
1731 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
1732 if (fpword & 0x20) flags |= _SW_INEXACT;
1733 fpword &= ~0x3f;
1734 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1736 #elif defined(__aarch64__)
1737 ULONG_PTR fpsr;
1739 __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
1740 if (fpsr & 0x1) flags |= _SW_INVALID;
1741 if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
1742 if (fpsr & 0x4) flags |= _SW_OVERFLOW;
1743 if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
1744 if (fpsr & 0x10) flags |= _SW_INEXACT;
1745 if (fpsr & 0x80) flags |= _SW_DENORMAL;
1746 fpsr &= ~0x9f;
1747 __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) );
1748 #else
1749 FIXME( "not implemented\n" );
1750 #endif
1751 return flags;
1754 /*********************************************************************
1755 * __fpecode (MSVCRT.@)
1757 int * CDECL __fpecode(void)
1759 return &msvcrt_get_thread_data()->fpecode;
1762 /*********************************************************************
1763 * ldexp (MSVCRT.@)
1765 double CDECL ldexp(double num, int exp)
1767 double z = unix_funcs->ldexp(num,exp);
1769 if (isfinite(num) && !isfinite(z))
1770 return math_error(_OVERFLOW, "ldexp", num, exp, z);
1771 if (num && isfinite(num) && !z)
1772 return math_error(_UNDERFLOW, "ldexp", num, exp, z);
1773 if (z == 0 && signbit(z))
1774 z = 0.0; /* Convert -0 -> +0 */
1775 return z;
1778 /*********************************************************************
1779 * _cabs (MSVCRT.@)
1781 double CDECL _cabs(struct _complex num)
1783 return sqrt(num.x * num.x + num.y * num.y);
1786 /*********************************************************************
1787 * _chgsign (MSVCRT.@)
1789 double CDECL _chgsign(double num)
1791 union { double f; UINT64 i; } u = { num };
1792 u.i ^= 1ull << 63;
1793 return u.f;
1796 /*********************************************************************
1797 * __control87_2 (MSVCR80.@)
1799 * Not exported by native msvcrt, added in msvcr80.
1801 #ifdef __i386__
1802 int CDECL __control87_2( unsigned int newval, unsigned int mask,
1803 unsigned int *x86_cw, unsigned int *sse2_cw )
1805 #if defined(__GNUC__) || defined(__clang__)
1806 unsigned long fpword;
1807 unsigned int flags;
1808 unsigned int old_flags;
1810 if (x86_cw)
1812 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
1814 /* Convert into mask constants */
1815 flags = 0;
1816 if (fpword & 0x1) flags |= _EM_INVALID;
1817 if (fpword & 0x2) flags |= _EM_DENORMAL;
1818 if (fpword & 0x4) flags |= _EM_ZERODIVIDE;
1819 if (fpword & 0x8) flags |= _EM_OVERFLOW;
1820 if (fpword & 0x10) flags |= _EM_UNDERFLOW;
1821 if (fpword & 0x20) flags |= _EM_INEXACT;
1822 switch (fpword & 0xc00)
1824 case 0xc00: flags |= _RC_UP|_RC_DOWN; break;
1825 case 0x800: flags |= _RC_UP; break;
1826 case 0x400: flags |= _RC_DOWN; break;
1828 switch (fpword & 0x300)
1830 case 0x0: flags |= _PC_24; break;
1831 case 0x200: flags |= _PC_53; break;
1832 case 0x300: flags |= _PC_64; break;
1834 if (fpword & 0x1000) flags |= _IC_AFFINE;
1836 TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1837 if (mask)
1839 flags = (flags & ~mask) | (newval & mask);
1841 /* Convert (masked) value back to fp word */
1842 fpword = 0;
1843 if (flags & _EM_INVALID) fpword |= 0x1;
1844 if (flags & _EM_DENORMAL) fpword |= 0x2;
1845 if (flags & _EM_ZERODIVIDE) fpword |= 0x4;
1846 if (flags & _EM_OVERFLOW) fpword |= 0x8;
1847 if (flags & _EM_UNDERFLOW) fpword |= 0x10;
1848 if (flags & _EM_INEXACT) fpword |= 0x20;
1849 switch (flags & _MCW_RC)
1851 case _RC_UP|_RC_DOWN: fpword |= 0xc00; break;
1852 case _RC_UP: fpword |= 0x800; break;
1853 case _RC_DOWN: fpword |= 0x400; break;
1855 switch (flags & _MCW_PC)
1857 case _PC_64: fpword |= 0x300; break;
1858 case _PC_53: fpword |= 0x200; break;
1859 case _PC_24: fpword |= 0x0; break;
1861 if (flags & _IC_AFFINE) fpword |= 0x1000;
1863 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1865 *x86_cw = flags;
1868 if (!sse2_cw) return 1;
1870 if (sse2_supported)
1872 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1874 /* Convert into mask constants */
1875 flags = 0;
1876 if (fpword & 0x80) flags |= _EM_INVALID;
1877 if (fpword & 0x100) flags |= _EM_DENORMAL;
1878 if (fpword & 0x200) flags |= _EM_ZERODIVIDE;
1879 if (fpword & 0x400) flags |= _EM_OVERFLOW;
1880 if (fpword & 0x800) flags |= _EM_UNDERFLOW;
1881 if (fpword & 0x1000) flags |= _EM_INEXACT;
1882 switch (fpword & 0x6000)
1884 case 0x6000: flags |= _RC_UP|_RC_DOWN; break;
1885 case 0x4000: flags |= _RC_UP; break;
1886 case 0x2000: flags |= _RC_DOWN; break;
1888 switch (fpword & 0x8040)
1890 case 0x0040: flags |= _DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1891 case 0x8000: flags |= _DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1892 case 0x8040: flags |= _DN_FLUSH; break;
1895 TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1896 if (mask)
1898 old_flags = flags;
1899 mask &= _MCW_EM | _MCW_RC | _MCW_DN;
1900 flags = (flags & ~mask) | (newval & mask);
1902 if (flags != old_flags)
1904 /* Convert (masked) value back to fp word */
1905 fpword = 0;
1906 if (flags & _EM_INVALID) fpword |= 0x80;
1907 if (flags & _EM_DENORMAL) fpword |= 0x100;
1908 if (flags & _EM_ZERODIVIDE) fpword |= 0x200;
1909 if (flags & _EM_OVERFLOW) fpword |= 0x400;
1910 if (flags & _EM_UNDERFLOW) fpword |= 0x800;
1911 if (flags & _EM_INEXACT) fpword |= 0x1000;
1912 switch (flags & _MCW_RC)
1914 case _RC_UP|_RC_DOWN: fpword |= 0x6000; break;
1915 case _RC_UP: fpword |= 0x4000; break;
1916 case _RC_DOWN: fpword |= 0x2000; break;
1918 switch (flags & _MCW_DN)
1920 case _DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1921 case _DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1922 case _DN_FLUSH: fpword |= 0x8040; break;
1924 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1927 *sse2_cw = flags;
1929 else *sse2_cw = 0;
1931 return 1;
1932 #else
1933 FIXME( "not implemented\n" );
1934 return 0;
1935 #endif
1937 #endif
1939 /*********************************************************************
1940 * _control87 (MSVCRT.@)
1942 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1944 unsigned int flags = 0;
1945 #ifdef __i386__
1946 unsigned int sse2_cw;
1948 __control87_2( newval, mask, &flags, &sse2_cw );
1950 if ((flags ^ sse2_cw) & (_MCW_EM | _MCW_RC)) flags |= _EM_AMBIGUOUS;
1951 flags |= sse2_cw;
1952 #elif defined(__x86_64__)
1953 unsigned long fpword;
1954 unsigned int old_flags;
1956 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1957 if (fpword & 0x80) flags |= _EM_INVALID;
1958 if (fpword & 0x100) flags |= _EM_DENORMAL;
1959 if (fpword & 0x200) flags |= _EM_ZERODIVIDE;
1960 if (fpword & 0x400) flags |= _EM_OVERFLOW;
1961 if (fpword & 0x800) flags |= _EM_UNDERFLOW;
1962 if (fpword & 0x1000) flags |= _EM_INEXACT;
1963 switch (fpword & 0x6000)
1965 case 0x6000: flags |= _RC_CHOP; break;
1966 case 0x4000: flags |= _RC_UP; break;
1967 case 0x2000: flags |= _RC_DOWN; break;
1969 switch (fpword & 0x8040)
1971 case 0x0040: flags |= _DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1972 case 0x8000: flags |= _DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1973 case 0x8040: flags |= _DN_FLUSH; break;
1975 old_flags = flags;
1976 mask &= _MCW_EM | _MCW_RC | _MCW_DN;
1977 flags = (flags & ~mask) | (newval & mask);
1978 if (flags != old_flags)
1980 fpword = 0;
1981 if (flags & _EM_INVALID) fpword |= 0x80;
1982 if (flags & _EM_DENORMAL) fpword |= 0x100;
1983 if (flags & _EM_ZERODIVIDE) fpword |= 0x200;
1984 if (flags & _EM_OVERFLOW) fpword |= 0x400;
1985 if (flags & _EM_UNDERFLOW) fpword |= 0x800;
1986 if (flags & _EM_INEXACT) fpword |= 0x1000;
1987 switch (flags & _MCW_RC)
1989 case _RC_CHOP: fpword |= 0x6000; break;
1990 case _RC_UP: fpword |= 0x4000; break;
1991 case _RC_DOWN: fpword |= 0x2000; break;
1993 switch (flags & _MCW_DN)
1995 case _DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1996 case _DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1997 case _DN_FLUSH: fpword |= 0x8040; break;
1999 __asm__ __volatile__( "ldmxcsr %0" :: "m" (fpword) );
2001 #elif defined(__aarch64__)
2002 ULONG_PTR fpcr;
2004 __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) );
2005 if (!(fpcr & 0x100)) flags |= _EM_INVALID;
2006 if (!(fpcr & 0x200)) flags |= _EM_ZERODIVIDE;
2007 if (!(fpcr & 0x400)) flags |= _EM_OVERFLOW;
2008 if (!(fpcr & 0x800)) flags |= _EM_UNDERFLOW;
2009 if (!(fpcr & 0x1000)) flags |= _EM_INEXACT;
2010 if (!(fpcr & 0x8000)) flags |= _EM_DENORMAL;
2011 switch (fpcr & 0xc00000)
2013 case 0x400000: flags |= _RC_UP; break;
2014 case 0x800000: flags |= _RC_DOWN; break;
2015 case 0xc00000: flags |= _RC_CHOP; break;
2017 flags = (flags & ~mask) | (newval & mask);
2018 fpcr &= ~0xc09f00ul;
2019 if (!(flags & _EM_INVALID)) fpcr |= 0x100;
2020 if (!(flags & _EM_ZERODIVIDE)) fpcr |= 0x200;
2021 if (!(flags & _EM_OVERFLOW)) fpcr |= 0x400;
2022 if (!(flags & _EM_UNDERFLOW)) fpcr |= 0x800;
2023 if (!(flags & _EM_INEXACT)) fpcr |= 0x1000;
2024 if (!(flags & _EM_DENORMAL)) fpcr |= 0x8000;
2025 switch (flags & _MCW_RC)
2027 case _RC_CHOP: fpcr |= 0xc00000; break;
2028 case _RC_UP: fpcr |= 0x400000; break;
2029 case _RC_DOWN: fpcr |= 0x800000; break;
2031 __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) );
2032 #else
2033 FIXME( "not implemented\n" );
2034 #endif
2035 return flags;
2038 /*********************************************************************
2039 * _controlfp (MSVCRT.@)
2041 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
2043 return _control87( newval, mask & ~_EM_DENORMAL );
2046 /*********************************************************************
2047 * _set_controlfp (MSVCRT.@)
2049 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
2051 _controlfp( newval, mask );
2054 /*********************************************************************
2055 * _controlfp_s (MSVCRT.@)
2057 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
2059 static const unsigned int all_flags = (_MCW_EM | _MCW_IC | _MCW_RC |
2060 _MCW_PC | _MCW_DN);
2061 unsigned int val;
2063 if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
2065 if (cur) *cur = _controlfp( 0, 0 ); /* retrieve it anyway */
2066 return EINVAL;
2068 val = _controlfp( newval, mask );
2069 if (cur) *cur = val;
2070 return 0;
2073 #if _MSVCR_VER>=120
2074 /*********************************************************************
2075 * fegetenv (MSVCR120.@)
2077 int CDECL fegetenv(fenv_t *env)
2079 env->_Fe_ctl = _controlfp(0, 0) & (_EM_INEXACT | _EM_UNDERFLOW |
2080 _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID | _RC_CHOP);
2081 env->_Fe_stat = _statusfp();
2082 return 0;
2084 #endif
2086 #if _MSVCR_VER>=140
2087 /*********************************************************************
2088 * __fpe_flt_rounds (UCRTBASE.@)
2090 int CDECL __fpe_flt_rounds(void)
2092 unsigned int fpc = _controlfp(0, 0) & _RC_CHOP;
2094 TRACE("()\n");
2096 switch(fpc) {
2097 case _RC_CHOP: return 0;
2098 case _RC_NEAR: return 1;
2099 case _RC_UP: return 2;
2100 default: return 3;
2103 #endif
2105 #if _MSVCR_VER>=120
2107 /*********************************************************************
2108 * fegetround (MSVCR120.@)
2110 int CDECL fegetround(void)
2112 return _controlfp(0, 0) & _RC_CHOP;
2115 /*********************************************************************
2116 * fesetround (MSVCR120.@)
2118 int CDECL fesetround(int round_mode)
2120 if (round_mode & (~_RC_CHOP))
2121 return 1;
2122 _controlfp(round_mode, _RC_CHOP);
2123 return 0;
2126 #endif /* _MSVCR_VER>=120 */
2128 /*********************************************************************
2129 * _copysign (MSVCRT.@)
2131 * Copied from musl: src/math/copysign.c
2133 double CDECL _copysign( double x, double y )
2135 union { double f; UINT64 i; } ux = { x }, uy = { y };
2136 ux.i &= ~0ull >> 1;
2137 ux.i |= uy.i & 1ull << 63;
2138 return ux.f;
2141 /*********************************************************************
2142 * _finite (MSVCRT.@)
2144 int CDECL _finite(double num)
2146 union { double f; UINT64 i; } u = { num };
2147 return (u.i & ~0ull >> 1) < 0x7ffull << 52;
2150 /*********************************************************************
2151 * _fpreset (MSVCRT.@)
2153 void CDECL _fpreset(void)
2155 #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
2156 const unsigned int x86_cw = 0x27f;
2157 __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
2158 if (sse2_supported)
2160 const unsigned long sse2_cw = 0x1f80;
2161 __asm__ __volatile__( "ldmxcsr %0" : : "m" (sse2_cw) );
2163 #else
2164 FIXME( "not implemented\n" );
2165 #endif
2168 #if _MSVCR_VER>=120
2169 /*********************************************************************
2170 * fesetenv (MSVCR120.@)
2172 int CDECL fesetenv(const fenv_t *env)
2174 #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
2175 struct {
2176 WORD control_word;
2177 WORD unused1;
2178 WORD status_word;
2179 WORD unused2;
2180 WORD tag_word;
2181 WORD unused3;
2182 DWORD instruction_pointer;
2183 WORD code_segment;
2184 WORD unused4;
2185 DWORD operand_addr;
2186 WORD data_segment;
2187 WORD unused5;
2188 } fenv;
2190 TRACE( "(%p)\n", env );
2192 if (!env->_Fe_ctl && !env->_Fe_stat) {
2193 _fpreset();
2194 return 0;
2197 __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
2199 fenv.control_word &= ~0xc3d;
2200 if (env->_Fe_ctl & _EM_INVALID) fenv.control_word |= 0x1;
2201 if (env->_Fe_ctl & _EM_ZERODIVIDE) fenv.control_word |= 0x4;
2202 if (env->_Fe_ctl & _EM_OVERFLOW) fenv.control_word |= 0x8;
2203 if (env->_Fe_ctl & _EM_UNDERFLOW) fenv.control_word |= 0x10;
2204 if (env->_Fe_ctl & _EM_INEXACT) fenv.control_word |= 0x20;
2205 switch (env->_Fe_ctl & _MCW_RC)
2207 case _RC_UP|_RC_DOWN: fenv.control_word |= 0xc00; break;
2208 case _RC_UP: fenv.control_word |= 0x800; break;
2209 case _RC_DOWN: fenv.control_word |= 0x400; break;
2212 fenv.status_word &= ~0x3d;
2213 if (env->_Fe_stat & FE_INVALID) fenv.status_word |= 0x1;
2214 if (env->_Fe_stat & FE_DIVBYZERO) fenv.status_word |= 0x4;
2215 if (env->_Fe_stat & FE_OVERFLOW) fenv.status_word |= 0x8;
2216 if (env->_Fe_stat & FE_UNDERFLOW) fenv.status_word |= 0x10;
2217 if (env->_Fe_stat & FE_INEXACT) fenv.status_word |= 0x20;
2219 __asm__ __volatile__( "fldenv %0" : : "m" (fenv) : "st", "st(1)",
2220 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
2222 if (sse2_supported)
2224 DWORD fpword;
2225 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
2226 fpword &= ~0x7e80;
2227 if (env->_Fe_ctl & _EM_INVALID) fpword |= 0x80;
2228 if (env->_Fe_ctl & _EM_ZERODIVIDE) fpword |= 0x200;
2229 if (env->_Fe_ctl & _EM_OVERFLOW) fpword |= 0x400;
2230 if (env->_Fe_ctl & _EM_UNDERFLOW) fpword |= 0x800;
2231 if (env->_Fe_ctl & _EM_INEXACT) fpword |= 0x1000;
2232 switch (env->_Fe_ctl & _MCW_RC)
2234 case _RC_CHOP: fpword |= 0x6000; break;
2235 case _RC_UP: fpword |= 0x4000; break;
2236 case _RC_DOWN: fpword |= 0x2000; break;
2238 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
2241 return 0;
2242 #else
2243 FIXME( "not implemented\n" );
2244 #endif
2245 return 1;
2247 #endif
2249 /*********************************************************************
2250 * _isnan (MSVCRT.@)
2252 int CDECL _isnan(double num)
2254 union { double f; UINT64 i; } u = { num };
2255 return (u.i & ~0ull >> 1) > 0x7ffull << 52;
2258 /*********************************************************************
2259 * _j0 (MSVCRT.@)
2261 double CDECL _j0(double num)
2263 /* FIXME: errno handling */
2264 return unix_funcs->j0( num );
2267 /*********************************************************************
2268 * _j1 (MSVCRT.@)
2270 double CDECL _j1(double num)
2272 /* FIXME: errno handling */
2273 return unix_funcs->j1( num );
2276 /*********************************************************************
2277 * _jn (MSVCRT.@)
2279 double CDECL _jn(int n, double num)
2281 /* FIXME: errno handling */
2282 return unix_funcs->jn( n, num );
2285 /*********************************************************************
2286 * _y0 (MSVCRT.@)
2288 double CDECL _y0(double num)
2290 double retval;
2292 if (!isfinite(num)) *_errno() = EDOM;
2293 retval = unix_funcs->y0( num );
2294 if (_fpclass(retval) == _FPCLASS_NINF)
2296 *_errno() = EDOM;
2297 retval = NAN;
2299 return retval;
2302 /*********************************************************************
2303 * _y1 (MSVCRT.@)
2305 double CDECL _y1(double num)
2307 double retval;
2309 if (!isfinite(num)) *_errno() = EDOM;
2310 retval = unix_funcs->y1( num );
2311 if (_fpclass(retval) == _FPCLASS_NINF)
2313 *_errno() = EDOM;
2314 retval = NAN;
2316 return retval;
2319 /*********************************************************************
2320 * _yn (MSVCRT.@)
2322 double CDECL _yn(int order, double num)
2324 double retval;
2326 if (!isfinite(num)) *_errno() = EDOM;
2327 retval = unix_funcs->yn( order, num );
2328 if (_fpclass(retval) == _FPCLASS_NINF)
2330 *_errno() = EDOM;
2331 retval = NAN;
2333 return retval;
2336 #if _MSVCR_VER>=120
2338 /*********************************************************************
2339 * _nearbyint (MSVCR120.@)
2341 double CDECL nearbyint(double num)
2343 return unix_funcs->nearbyint( num );
2346 /*********************************************************************
2347 * _nearbyintf (MSVCR120.@)
2349 float CDECL nearbyintf(float num)
2351 return unix_funcs->nearbyintf( num );
2354 /*********************************************************************
2355 * nexttoward (MSVCR120.@)
2357 double CDECL MSVCRT_nexttoward(double num, double next)
2359 double ret = unix_funcs->nexttoward(num, next);
2360 if (!(_fpclass(ret) & (_FPCLASS_PN | _FPCLASS_NN
2361 | _FPCLASS_SNAN | _FPCLASS_QNAN)) && !isinf(num))
2363 *_errno() = ERANGE;
2365 return ret;
2368 /*********************************************************************
2369 * nexttowardf (MSVCR120.@)
2371 float CDECL MSVCRT_nexttowardf(float num, double next)
2373 float ret = unix_funcs->nexttowardf( num, next );
2374 if (!(_fpclass(ret) & (_FPCLASS_PN | _FPCLASS_NN
2375 | _FPCLASS_SNAN | _FPCLASS_QNAN)) && !isinf(num))
2377 *_errno() = ERANGE;
2379 return ret;
2382 #endif /* _MSVCR_VER>=120 */
2384 /*********************************************************************
2385 * _nextafter (MSVCRT.@)
2387 double CDECL _nextafter(double num, double next)
2389 double retval;
2390 if (!isfinite(num) || !isfinite(next)) *_errno() = EDOM;
2391 retval = unix_funcs->nextafter(num,next);
2392 return retval;
2395 /*********************************************************************
2396 * _ecvt (MSVCRT.@)
2398 char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
2400 int prec, len;
2401 thread_data_t *data = msvcrt_get_thread_data();
2402 /* FIXME: check better for overflow (native supports over 300 chars) */
2403 ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
2404 * 4 for exponent and one for
2405 * terminating '\0' */
2406 if (!data->efcvt_buffer)
2407 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
2409 if( number < 0) {
2410 *sign = TRUE;
2411 number = -number;
2412 } else
2413 *sign = FALSE;
2414 /* handle cases with zero ndigits or less */
2415 prec = ndigits;
2416 if( prec < 1) prec = 2;
2417 len = _snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
2418 /* take the decimal "point away */
2419 if( prec != 1)
2420 memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
2421 /* take the exponential "e" out */
2422 data->efcvt_buffer[ prec] = '\0';
2423 /* read the exponent */
2424 sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
2425 (*decpt)++;
2426 /* adjust for some border cases */
2427 if( data->efcvt_buffer[0] == '0')/* value is zero */
2428 *decpt = 0;
2429 /* handle cases with zero ndigits or less */
2430 if( ndigits < 1){
2431 if( data->efcvt_buffer[ 0] >= '5')
2432 (*decpt)++;
2433 data->efcvt_buffer[ 0] = '\0';
2435 TRACE("out=\"%s\"\n",data->efcvt_buffer);
2436 return data->efcvt_buffer;
2439 /*********************************************************************
2440 * _ecvt_s (MSVCRT.@)
2442 int CDECL _ecvt_s( char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign )
2444 int prec, len;
2445 char *result;
2446 const char infret[] = "1#INF";
2448 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
2449 if (!MSVCRT_CHECK_PMT(decpt != NULL)) return EINVAL;
2450 if (!MSVCRT_CHECK_PMT(sign != NULL)) return EINVAL;
2451 if (!MSVCRT_CHECK_PMT_ERR( length > 2, ERANGE )) return ERANGE;
2452 if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, ERANGE )) return ERANGE;
2454 /* special case - inf */
2455 if(number == HUGE_VAL || number == -HUGE_VAL)
2457 memset(buffer, '0', ndigits);
2458 memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
2459 buffer[ndigits] = '\0';
2460 (*decpt) = 1;
2461 if(number == -HUGE_VAL)
2462 (*sign) = 1;
2463 else
2464 (*sign) = 0;
2465 return 0;
2467 /* handle cases with zero ndigits or less */
2468 prec = ndigits;
2469 if( prec < 1) prec = 2;
2470 result = malloc(prec + 7);
2472 if( number < 0) {
2473 *sign = TRUE;
2474 number = -number;
2475 } else
2476 *sign = FALSE;
2477 len = _snprintf(result, prec + 7, "%.*le", prec - 1, number);
2478 /* take the decimal "point away */
2479 if( prec != 1)
2480 memmove( result + 1, result + 2, len - 1 );
2481 /* take the exponential "e" out */
2482 result[ prec] = '\0';
2483 /* read the exponent */
2484 sscanf( result + prec + 1, "%d", decpt);
2485 (*decpt)++;
2486 /* adjust for some border cases */
2487 if( result[0] == '0')/* value is zero */
2488 *decpt = 0;
2489 /* handle cases with zero ndigits or less */
2490 if( ndigits < 1){
2491 if( result[ 0] >= '5')
2492 (*decpt)++;
2493 result[ 0] = '\0';
2495 memcpy( buffer, result, max(ndigits + 1, 1) );
2496 free( result );
2497 return 0;
2500 /***********************************************************************
2501 * _fcvt (MSVCRT.@)
2503 char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
2505 thread_data_t *data = msvcrt_get_thread_data();
2506 int stop, dec1, dec2;
2507 char *ptr1, *ptr2, *first;
2508 char buf[80]; /* ought to be enough */
2509 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
2511 if (!data->efcvt_buffer)
2512 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
2514 if (number < 0)
2516 *sign = 1;
2517 number = -number;
2518 } else *sign = 0;
2520 stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
2521 ptr1 = buf;
2522 ptr2 = data->efcvt_buffer;
2523 first = NULL;
2524 dec1 = 0;
2525 dec2 = 0;
2527 /* For numbers below the requested resolution, work out where
2528 the decimal point will be rather than finding it in the string */
2529 if (number < 1.0 && number > 0.0) {
2530 dec2 = log10(number + 1e-10);
2531 if (-dec2 <= ndigits) dec2 = 0;
2534 /* If requested digits is zero or less, we will need to truncate
2535 * the returned string */
2536 if (ndigits < 1) {
2537 stop += ndigits;
2540 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
2541 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
2542 if (!first) first = ptr2;
2543 if ((ptr1 - buf) < stop) {
2544 *ptr2++ = *ptr1++;
2545 } else {
2546 ptr1++;
2548 dec1++;
2551 if (ndigits > 0) {
2552 ptr1++;
2553 if (!first) {
2554 while (*ptr1 == '0') { /* Process leading zeroes */
2555 *ptr2++ = *ptr1++;
2556 dec1--;
2559 while (*ptr1 != '\0') {
2560 if (!first) first = ptr2;
2561 *ptr2++ = *ptr1++;
2565 *ptr2 = '\0';
2567 /* We never found a non-zero digit, then our number is either
2568 * smaller than the requested precision, or 0.0 */
2569 if (!first) {
2570 if (number > 0.0) {
2571 first = ptr2;
2572 } else {
2573 first = data->efcvt_buffer;
2574 dec1 = 0;
2578 *decpt = dec2 ? dec2 : dec1;
2579 return first;
2582 /***********************************************************************
2583 * _fcvt_s (MSVCRT.@)
2585 int CDECL _fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int *decpt, int *sign)
2587 int stop, dec1, dec2;
2588 char *ptr1, *ptr2, *first;
2589 char buf[80]; /* ought to be enough */
2590 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
2592 if (!outbuffer || !decpt || !sign || size == 0)
2594 *_errno() = EINVAL;
2595 return EINVAL;
2598 if (number < 0)
2600 *sign = 1;
2601 number = -number;
2602 } else *sign = 0;
2604 stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
2605 ptr1 = buf;
2606 ptr2 = outbuffer;
2607 first = NULL;
2608 dec1 = 0;
2609 dec2 = 0;
2611 /* For numbers below the requested resolution, work out where
2612 the decimal point will be rather than finding it in the string */
2613 if (number < 1.0 && number > 0.0) {
2614 dec2 = log10(number + 1e-10);
2615 if (-dec2 <= ndigits) dec2 = 0;
2618 /* If requested digits is zero or less, we will need to truncate
2619 * the returned string */
2620 if (ndigits < 1) {
2621 stop += ndigits;
2624 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
2625 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
2626 if (!first) first = ptr2;
2627 if ((ptr1 - buf) < stop) {
2628 if (size > 1) {
2629 *ptr2++ = *ptr1++;
2630 size--;
2632 } else {
2633 ptr1++;
2635 dec1++;
2638 if (ndigits > 0) {
2639 ptr1++;
2640 if (!first) {
2641 while (*ptr1 == '0') { /* Process leading zeroes */
2642 if (number == 0.0 && size > 1) {
2643 *ptr2++ = '0';
2644 size--;
2646 ptr1++;
2647 dec1--;
2650 while (*ptr1 != '\0') {
2651 if (!first) first = ptr2;
2652 if (size > 1) {
2653 *ptr2++ = *ptr1++;
2654 size--;
2659 *ptr2 = '\0';
2661 /* We never found a non-zero digit, then our number is either
2662 * smaller than the requested precision, or 0.0 */
2663 if (!first && (number <= 0.0))
2664 dec1 = 0;
2666 *decpt = dec2 ? dec2 : dec1;
2667 return 0;
2670 /***********************************************************************
2671 * _gcvt (MSVCRT.@)
2673 char * CDECL _gcvt( double number, int ndigit, char *buff )
2675 if(!buff) {
2676 *_errno() = EINVAL;
2677 return NULL;
2680 if(ndigit < 0) {
2681 *_errno() = ERANGE;
2682 return NULL;
2685 sprintf(buff, "%.*g", ndigit, number);
2686 return buff;
2689 /***********************************************************************
2690 * _gcvt_s (MSVCRT.@)
2692 int CDECL _gcvt_s(char *buff, size_t size, double number, int digits)
2694 int len;
2696 if(!buff) {
2697 *_errno() = EINVAL;
2698 return EINVAL;
2701 if( digits<0 || digits>=size) {
2702 if(size)
2703 buff[0] = '\0';
2705 *_errno() = ERANGE;
2706 return ERANGE;
2709 len = _scprintf("%.*g", digits, number);
2710 if(len > size) {
2711 buff[0] = '\0';
2712 *_errno() = ERANGE;
2713 return ERANGE;
2716 sprintf(buff, "%.*g", digits, number);
2717 return 0;
2720 #include <stdlib.h> /* div_t, ldiv_t */
2722 /*********************************************************************
2723 * div (MSVCRT.@)
2724 * VERSION
2725 * [i386] Windows binary compatible - returns the struct in eax/edx.
2727 #ifdef __i386__
2728 unsigned __int64 CDECL div(int num, int denom)
2730 union {
2731 div_t div;
2732 unsigned __int64 uint64;
2733 } ret;
2735 ret.div.quot = num / denom;
2736 ret.div.rem = num % denom;
2737 return ret.uint64;
2739 #else
2740 /*********************************************************************
2741 * div (MSVCRT.@)
2742 * VERSION
2743 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2745 div_t CDECL div(int num, int denom)
2747 div_t ret;
2749 ret.quot = num / denom;
2750 ret.rem = num % denom;
2751 return ret;
2753 #endif /* ifdef __i386__ */
2756 /*********************************************************************
2757 * ldiv (MSVCRT.@)
2758 * VERSION
2759 * [i386] Windows binary compatible - returns the struct in eax/edx.
2761 #ifdef __i386__
2762 unsigned __int64 CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
2764 union {
2765 ldiv_t ldiv;
2766 unsigned __int64 uint64;
2767 } ret;
2769 ret.ldiv.quot = num / denom;
2770 ret.ldiv.rem = num % denom;
2771 return ret.uint64;
2773 #else
2774 /*********************************************************************
2775 * ldiv (MSVCRT.@)
2776 * VERSION
2777 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2779 ldiv_t CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
2781 ldiv_t ret;
2783 ret.quot = num / denom;
2784 ret.rem = num % denom;
2785 return ret;
2787 #endif /* ifdef __i386__ */
2789 #if _MSVCR_VER>=100
2790 /*********************************************************************
2791 * lldiv (MSVCR100.@)
2793 lldiv_t CDECL lldiv(__int64 num, __int64 denom)
2795 lldiv_t ret;
2797 ret.quot = num / denom;
2798 ret.rem = num % denom;
2800 return ret;
2802 #endif
2804 #ifdef __i386__
2806 /*********************************************************************
2807 * _adjust_fdiv (MSVCRT.@)
2808 * Used by the MSVC compiler to work around the Pentium FDIV bug.
2810 int MSVCRT__adjust_fdiv = 0;
2812 /***********************************************************************
2813 * _adj_fdiv_m16i (MSVCRT.@)
2815 * NOTE
2816 * I _think_ this function is intended to work around the Pentium
2817 * fdiv bug.
2819 void __stdcall _adj_fdiv_m16i( short arg )
2821 TRACE("(): stub\n");
2824 /***********************************************************************
2825 * _adj_fdiv_m32 (MSVCRT.@)
2827 * NOTE
2828 * I _think_ this function is intended to work around the Pentium
2829 * fdiv bug.
2831 void __stdcall _adj_fdiv_m32( unsigned int arg )
2833 TRACE("(): stub\n");
2836 /***********************************************************************
2837 * _adj_fdiv_m32i (MSVCRT.@)
2839 * NOTE
2840 * I _think_ this function is intended to work around the Pentium
2841 * fdiv bug.
2843 void __stdcall _adj_fdiv_m32i( int arg )
2845 TRACE("(): stub\n");
2848 /***********************************************************************
2849 * _adj_fdiv_m64 (MSVCRT.@)
2851 * NOTE
2852 * I _think_ this function is intended to work around the Pentium
2853 * fdiv bug.
2855 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
2857 TRACE("(): stub\n");
2860 /***********************************************************************
2861 * _adj_fdiv_r (MSVCRT.@)
2862 * FIXME
2863 * This function is likely to have the wrong number of arguments.
2865 * NOTE
2866 * I _think_ this function is intended to work around the Pentium
2867 * fdiv bug.
2869 void _adj_fdiv_r(void)
2871 TRACE("(): stub\n");
2874 /***********************************************************************
2875 * _adj_fdivr_m16i (MSVCRT.@)
2877 * NOTE
2878 * I _think_ this function is intended to work around the Pentium
2879 * fdiv bug.
2881 void __stdcall _adj_fdivr_m16i( short arg )
2883 TRACE("(): stub\n");
2886 /***********************************************************************
2887 * _adj_fdivr_m32 (MSVCRT.@)
2889 * NOTE
2890 * I _think_ this function is intended to work around the Pentium
2891 * fdiv bug.
2893 void __stdcall _adj_fdivr_m32( unsigned int arg )
2895 TRACE("(): stub\n");
2898 /***********************************************************************
2899 * _adj_fdivr_m32i (MSVCRT.@)
2901 * NOTE
2902 * I _think_ this function is intended to work around the Pentium
2903 * fdiv bug.
2905 void __stdcall _adj_fdivr_m32i( int arg )
2907 TRACE("(): stub\n");
2910 /***********************************************************************
2911 * _adj_fdivr_m64 (MSVCRT.@)
2913 * NOTE
2914 * I _think_ this function is intended to work around the Pentium
2915 * fdiv bug.
2917 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
2919 TRACE("(): stub\n");
2922 /***********************************************************************
2923 * _adj_fpatan (MSVCRT.@)
2924 * FIXME
2925 * This function is likely to have the wrong number of arguments.
2927 * NOTE
2928 * I _think_ this function is intended to work around the Pentium
2929 * fdiv bug.
2931 void _adj_fpatan(void)
2933 TRACE("(): stub\n");
2936 /***********************************************************************
2937 * _adj_fprem (MSVCRT.@)
2938 * FIXME
2939 * This function is likely to have the wrong number of arguments.
2941 * NOTE
2942 * I _think_ this function is intended to work around the Pentium
2943 * fdiv bug.
2945 void _adj_fprem(void)
2947 TRACE("(): stub\n");
2950 /***********************************************************************
2951 * _adj_fprem1 (MSVCRT.@)
2952 * FIXME
2953 * This function is likely to have the wrong number of arguments.
2955 * NOTE
2956 * I _think_ this function is intended to work around the Pentium
2957 * fdiv bug.
2959 void _adj_fprem1(void)
2961 TRACE("(): stub\n");
2964 /***********************************************************************
2965 * _adj_fptan (MSVCRT.@)
2966 * FIXME
2967 * This function is likely to have the wrong number of arguments.
2969 * NOTE
2970 * I _think_ this function is intended to work around the Pentium
2971 * fdiv bug.
2973 void _adj_fptan(void)
2975 TRACE("(): stub\n");
2978 /***********************************************************************
2979 * _safe_fdiv (MSVCRT.@)
2980 * FIXME
2981 * This function is likely to have the wrong number of arguments.
2983 * NOTE
2984 * I _think_ this function is intended to work around the Pentium
2985 * fdiv bug.
2987 void _safe_fdiv(void)
2989 TRACE("(): stub\n");
2992 /***********************************************************************
2993 * _safe_fdivr (MSVCRT.@)
2994 * FIXME
2995 * This function is likely to have the wrong number of arguments.
2997 * NOTE
2998 * I _think_ this function is intended to work around the Pentium
2999 * fdiv bug.
3001 void _safe_fdivr(void)
3003 TRACE("(): stub\n");
3006 /***********************************************************************
3007 * _safe_fprem (MSVCRT.@)
3008 * FIXME
3009 * This function is likely to have the wrong number of arguments.
3011 * NOTE
3012 * I _think_ this function is intended to work around the Pentium
3013 * fdiv bug.
3015 void _safe_fprem(void)
3017 TRACE("(): stub\n");
3020 /***********************************************************************
3021 * _safe_fprem1 (MSVCRT.@)
3023 * FIXME
3024 * This function is likely to have the wrong number of arguments.
3026 * NOTE
3027 * I _think_ this function is intended to work around the Pentium
3028 * fdiv bug.
3030 void _safe_fprem1(void)
3032 TRACE("(): stub\n");
3035 /***********************************************************************
3036 * __libm_sse2_acos (MSVCRT.@)
3038 void __cdecl __libm_sse2_acos(void)
3040 double d;
3041 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3042 d = acos( d );
3043 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3046 /***********************************************************************
3047 * __libm_sse2_acosf (MSVCRT.@)
3049 void __cdecl __libm_sse2_acosf(void)
3051 float f;
3052 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3053 f = acosf( f );
3054 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3057 /***********************************************************************
3058 * __libm_sse2_asin (MSVCRT.@)
3060 void __cdecl __libm_sse2_asin(void)
3062 double d;
3063 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3064 d = asin( d );
3065 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3068 /***********************************************************************
3069 * __libm_sse2_asinf (MSVCRT.@)
3071 void __cdecl __libm_sse2_asinf(void)
3073 float f;
3074 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3075 f = asinf( f );
3076 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3079 /***********************************************************************
3080 * __libm_sse2_atan (MSVCRT.@)
3082 void __cdecl __libm_sse2_atan(void)
3084 double d;
3085 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3086 d = atan( d );
3087 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3090 /***********************************************************************
3091 * __libm_sse2_atan2 (MSVCRT.@)
3093 void __cdecl __libm_sse2_atan2(void)
3095 double d1, d2;
3096 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
3097 d1 = atan2( d1, d2 );
3098 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
3101 /***********************************************************************
3102 * __libm_sse2_atanf (MSVCRT.@)
3104 void __cdecl __libm_sse2_atanf(void)
3106 float f;
3107 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3108 f = atanf( f );
3109 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3112 /***********************************************************************
3113 * __libm_sse2_cos (MSVCRT.@)
3115 void __cdecl __libm_sse2_cos(void)
3117 double d;
3118 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3119 d = cos( d );
3120 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3123 /***********************************************************************
3124 * __libm_sse2_cosf (MSVCRT.@)
3126 void __cdecl __libm_sse2_cosf(void)
3128 float f;
3129 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3130 f = cosf( f );
3131 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3134 /***********************************************************************
3135 * __libm_sse2_exp (MSVCRT.@)
3137 void __cdecl __libm_sse2_exp(void)
3139 double d;
3140 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3141 d = exp( d );
3142 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3145 /***********************************************************************
3146 * __libm_sse2_expf (MSVCRT.@)
3148 void __cdecl __libm_sse2_expf(void)
3150 float f;
3151 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3152 f = expf( f );
3153 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3156 /***********************************************************************
3157 * __libm_sse2_log (MSVCRT.@)
3159 void __cdecl __libm_sse2_log(void)
3161 double d;
3162 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3163 d = log( d );
3164 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3167 /***********************************************************************
3168 * __libm_sse2_log10 (MSVCRT.@)
3170 void __cdecl __libm_sse2_log10(void)
3172 double d;
3173 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3174 d = log10( d );
3175 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3178 /***********************************************************************
3179 * __libm_sse2_log10f (MSVCRT.@)
3181 void __cdecl __libm_sse2_log10f(void)
3183 float f;
3184 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3185 f = log10f( f );
3186 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3189 /***********************************************************************
3190 * __libm_sse2_logf (MSVCRT.@)
3192 void __cdecl __libm_sse2_logf(void)
3194 float f;
3195 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3196 f = logf( f );
3197 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3200 /***********************************************************************
3201 * __libm_sse2_pow (MSVCRT.@)
3203 void __cdecl __libm_sse2_pow(void)
3205 double d1, d2;
3206 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
3207 d1 = pow( d1, d2 );
3208 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
3211 /***********************************************************************
3212 * __libm_sse2_powf (MSVCRT.@)
3214 void __cdecl __libm_sse2_powf(void)
3216 float f1, f2;
3217 __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
3218 f1 = powf( f1, f2 );
3219 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
3222 /***********************************************************************
3223 * __libm_sse2_sin (MSVCRT.@)
3225 void __cdecl __libm_sse2_sin(void)
3227 double d;
3228 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3229 d = sin( d );
3230 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3233 /***********************************************************************
3234 * __libm_sse2_sinf (MSVCRT.@)
3236 void __cdecl __libm_sse2_sinf(void)
3238 float f;
3239 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3240 f = sinf( f );
3241 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3244 /***********************************************************************
3245 * __libm_sse2_tan (MSVCRT.@)
3247 void __cdecl __libm_sse2_tan(void)
3249 double d;
3250 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3251 d = tan( d );
3252 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3255 /***********************************************************************
3256 * __libm_sse2_tanf (MSVCRT.@)
3258 void __cdecl __libm_sse2_tanf(void)
3260 float f;
3261 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
3262 f = tanf( f );
3263 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
3266 /***********************************************************************
3267 * __libm_sse2_sqrt_precise (MSVCR110.@)
3269 void __cdecl __libm_sse2_sqrt_precise(void)
3271 double d;
3272 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
3273 d = sqrt( d );
3274 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
3277 #endif /* __i386__ */
3279 /*********************************************************************
3280 * cbrt (MSVCR120.@)
3282 double CDECL cbrt(double x)
3284 return unix_funcs->cbrt( x );
3287 /*********************************************************************
3288 * cbrtf (MSVCR120.@)
3290 float CDECL cbrtf(float x)
3292 return unix_funcs->cbrtf( x );
3295 /*********************************************************************
3296 * exp2 (MSVCR120.@)
3298 double CDECL exp2(double x)
3300 double ret = unix_funcs->exp2( x );
3301 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3302 return ret;
3305 /*********************************************************************
3306 * exp2f (MSVCR120.@)
3308 float CDECL exp2f(float x)
3310 float ret = unix_funcs->exp2f( x );
3311 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3312 return ret;
3315 /*********************************************************************
3316 * expm1 (MSVCR120.@)
3318 double CDECL expm1(double x)
3320 double ret = unix_funcs->expm1( x );
3321 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3322 return ret;
3325 /*********************************************************************
3326 * expm1f (MSVCR120.@)
3328 float CDECL expm1f(float x)
3330 float ret = unix_funcs->expm1f( x );
3331 if (isfinite(x) && !isfinite(ret)) *_errno() = ERANGE;
3332 return ret;
3335 /*********************************************************************
3336 * log1p (MSVCR120.@)
3338 double CDECL log1p(double x)
3340 if (x < -1) *_errno() = EDOM;
3341 else if (x == -1) *_errno() = ERANGE;
3342 return unix_funcs->log1p( x );
3345 /*********************************************************************
3346 * log1pf (MSVCR120.@)
3348 float CDECL log1pf(float x)
3350 if (x < -1) *_errno() = EDOM;
3351 else if (x == -1) *_errno() = ERANGE;
3352 return unix_funcs->log1pf( x );
3355 /*********************************************************************
3356 * log2 (MSVCR120.@)
3358 double CDECL log2(double x)
3360 if (x < 0) *_errno() = EDOM;
3361 else if (x == 0) *_errno() = ERANGE;
3362 return unix_funcs->log2( x );
3365 /*********************************************************************
3366 * log2f (MSVCR120.@)
3368 float CDECL log2f(float x)
3370 if (x < 0) *_errno() = EDOM;
3371 else if (x == 0) *_errno() = ERANGE;
3372 return unix_funcs->log2f( x );
3375 /*********************************************************************
3376 * rint (MSVCR120.@)
3378 double CDECL rint(double x)
3380 return unix_funcs->rint(x);
3383 /*********************************************************************
3384 * rintf (MSVCR120.@)
3386 float CDECL rintf(float x)
3388 return unix_funcs->rintf(x);
3391 /*********************************************************************
3392 * lrint (MSVCR120.@)
3394 __msvcrt_long CDECL lrint(double x)
3396 return unix_funcs->lrint( x );
3399 /*********************************************************************
3400 * lrintf (MSVCR120.@)
3402 __msvcrt_long CDECL lrintf(float x)
3404 return unix_funcs->lrintf( x );
3407 /*********************************************************************
3408 * llrint (MSVCR120.@)
3410 __int64 CDECL llrint(double x)
3412 return unix_funcs->llrint( x );
3415 /*********************************************************************
3416 * llrintf (MSVCR120.@)
3418 __int64 CDECL llrintf(float x)
3420 return unix_funcs->llrintf( x );
3423 #if _MSVCR_VER>=120
3425 /*********************************************************************
3426 * round (MSVCR120.@)
3428 double CDECL round(double x)
3430 return unix_funcs->round(x);
3433 /*********************************************************************
3434 * roundf (MSVCR120.@)
3436 float CDECL roundf(float x)
3438 return unix_funcs->roundf(x);
3441 /*********************************************************************
3442 * lround (MSVCR120.@)
3444 __msvcrt_long CDECL lround(double x)
3446 return unix_funcs->lround( x );
3449 /*********************************************************************
3450 * lroundf (MSVCR120.@)
3452 __msvcrt_long CDECL lroundf(float x)
3454 return unix_funcs->lroundf( x );
3457 /*********************************************************************
3458 * llround (MSVCR120.@)
3460 __int64 CDECL llround(double x)
3462 return unix_funcs->llround( x );
3465 /*********************************************************************
3466 * llroundf (MSVCR120.@)
3468 __int64 CDECL llroundf(float x)
3470 return unix_funcs->llroundf( x );
3473 /*********************************************************************
3474 * trunc (MSVCR120.@)
3476 double CDECL trunc(double x)
3478 return unix_funcs->trunc(x);
3481 /*********************************************************************
3482 * truncf (MSVCR120.@)
3484 float CDECL truncf(float x)
3486 return unix_funcs->truncf(x);
3489 /*********************************************************************
3490 * _dclass (MSVCR120.@)
3492 * Copied from musl: src/math/__fpclassify.c
3494 short CDECL _dclass(double x)
3496 union { double f; UINT64 i; } u = { x };
3497 int e = u.i >> 52 & 0x7ff;
3499 if (!e) return u.i << 1 ? FP_SUBNORMAL : FP_ZERO;
3500 if (e == 0x7ff) return (u.i << 12) ? FP_NAN : FP_INFINITE;
3501 return FP_NORMAL;
3504 /*********************************************************************
3505 * _fdclass (MSVCR120.@)
3507 * Copied from musl: src/math/__fpclassifyf.c
3509 short CDECL _fdclass(float x)
3511 union { float f; UINT32 i; } u = { x };
3512 int e = u.i >> 23 & 0xff;
3514 if (!e) return u.i << 1 ? FP_SUBNORMAL : FP_ZERO;
3515 if (e == 0xff) return u.i << 9 ? FP_NAN : FP_INFINITE;
3516 return FP_NORMAL;
3519 /*********************************************************************
3520 * _dtest (MSVCR120.@)
3522 short CDECL _dtest(double *x)
3524 return _dclass(*x);
3527 /*********************************************************************
3528 * _fdtest (MSVCR120.@)
3530 short CDECL _fdtest(float *x)
3532 return _fdclass(*x);
3535 /*********************************************************************
3536 * erf (MSVCR120.@)
3538 double CDECL erf(double x)
3540 return unix_funcs->erf( x );
3543 /*********************************************************************
3544 * erff (MSVCR120.@)
3546 float CDECL erff(float x)
3548 return unix_funcs->erff( x );
3551 /*********************************************************************
3552 * erfc (MSVCR120.@)
3554 double CDECL erfc(double x)
3556 return unix_funcs->erfc( x );
3559 /*********************************************************************
3560 * erfcf (MSVCR120.@)
3562 float CDECL erfcf(float x)
3564 return unix_funcs->erfcf( x );
3567 /*********************************************************************
3568 * fmaxf (MSVCR120.@)
3570 float CDECL fmaxf(float x, float y)
3572 if(isnan(x))
3573 return y;
3574 if(isnan(y))
3575 return x;
3576 if(x==0 && y==0)
3577 return signbit(x) ? y : x;
3578 return x<y ? y : x;
3581 /*********************************************************************
3582 * fmax (MSVCR120.@)
3584 double CDECL fmax(double x, double y)
3586 if(isnan(x))
3587 return y;
3588 if(isnan(y))
3589 return x;
3590 if(x==0 && y==0)
3591 return signbit(x) ? y : x;
3592 return x<y ? y : x;
3595 /*********************************************************************
3596 * fdimf (MSVCR120.@)
3598 float CDECL fdimf(float x, float y)
3600 if(isnan(x))
3601 return x;
3602 if(isnan(y))
3603 return y;
3604 return x>y ? x-y : 0;
3607 /*********************************************************************
3608 * fdim (MSVCR120.@)
3610 double CDECL fdim(double x, double y)
3612 if(isnan(x))
3613 return x;
3614 if(isnan(y))
3615 return y;
3616 return x>y ? x-y : 0;
3619 /*********************************************************************
3620 * _fdsign (MSVCR120.@)
3622 int CDECL _fdsign(float x)
3624 union { float f; UINT32 i; } u = { x };
3625 return (u.i >> 16) & 0x8000;
3628 /*********************************************************************
3629 * _dsign (MSVCR120.@)
3631 int CDECL _dsign(double x)
3633 union { double f; UINT64 i; } u = { x };
3634 return (u.i >> 48) & 0x8000;
3638 /*********************************************************************
3639 * _dpcomp (MSVCR120.@)
3641 int CDECL _dpcomp(double x, double y)
3643 if(isnan(x) || isnan(y))
3644 return 0;
3646 if(x == y) return 2;
3647 return x < y ? 1 : 4;
3650 /*********************************************************************
3651 * _fdpcomp (MSVCR120.@)
3653 int CDECL _fdpcomp(float x, float y)
3655 return _dpcomp(x, y);
3658 /*********************************************************************
3659 * fminf (MSVCR120.@)
3661 float CDECL fminf(float x, float y)
3663 if(isnan(x))
3664 return y;
3665 if(isnan(y))
3666 return x;
3667 if(x==0 && y==0)
3668 return signbit(x) ? x : y;
3669 return x<y ? x : y;
3672 /*********************************************************************
3673 * fmin (MSVCR120.@)
3675 double CDECL fmin(double x, double y)
3677 if(isnan(x))
3678 return y;
3679 if(isnan(y))
3680 return x;
3681 if(x==0 && y==0)
3682 return signbit(x) ? x : y;
3683 return x<y ? x : y;
3686 /*********************************************************************
3687 * asinh (MSVCR120.@)
3689 double CDECL asinh(double x)
3691 return unix_funcs->asinh( x );
3694 /*********************************************************************
3695 * asinhf (MSVCR120.@)
3697 float CDECL asinhf(float x)
3699 return unix_funcs->asinhf( x );
3702 /*********************************************************************
3703 * acosh (MSVCR120.@)
3705 double CDECL acosh(double x)
3707 if (x < 1)
3709 fenv_t env;
3711 *_errno() = EDOM;
3712 fegetenv(&env);
3713 env._Fe_stat |= FE_INVALID;
3714 fesetenv(&env);
3715 return NAN;
3717 return unix_funcs->acosh( x );
3720 /*********************************************************************
3721 * acoshf (MSVCR120.@)
3723 float CDECL acoshf(float x)
3725 if (x < 1)
3727 fenv_t env;
3729 *_errno() = EDOM;
3730 fegetenv(&env);
3731 env._Fe_stat |= FE_INVALID;
3732 fesetenv(&env);
3733 return NAN;
3735 return unix_funcs->acoshf( x );
3738 /*********************************************************************
3739 * atanh (MSVCR120.@)
3741 double CDECL atanh(double x)
3743 double ret;
3745 if (x > 1 || x < -1) {
3746 fenv_t env;
3748 *_errno() = EDOM;
3750 /* on Linux atanh returns -NAN in this case */
3751 fegetenv(&env);
3752 env._Fe_stat |= FE_INVALID;
3753 fesetenv(&env);
3754 return NAN;
3756 ret = unix_funcs->atanh( x );
3758 if (!isfinite(ret)) *_errno() = ERANGE;
3759 return ret;
3762 /*********************************************************************
3763 * atanhf (MSVCR120.@)
3765 float CDECL atanhf(float x)
3767 float ret;
3769 if (x > 1 || x < -1) {
3770 fenv_t env;
3772 *_errno() = EDOM;
3774 fegetenv(&env);
3775 env._Fe_stat |= FE_INVALID;
3776 fesetenv(&env);
3777 return NAN;
3780 ret = unix_funcs->atanh( x );
3782 if (!isfinite(ret)) *_errno() = ERANGE;
3783 return ret;
3786 #endif /* _MSVCR_VER>=120 */
3788 /*********************************************************************
3789 * _scalb (MSVCRT.@)
3790 * scalbn (MSVCR120.@)
3791 * scalbln (MSVCR120.@)
3793 double CDECL _scalb(double num, __msvcrt_long power)
3795 return ldexp(num, power);
3798 /*********************************************************************
3799 * _scalbf (MSVCRT.@)
3800 * scalbnf (MSVCR120.@)
3801 * scalblnf (MSVCR120.@)
3803 float CDECL _scalbf(float num, __msvcrt_long power)
3805 return ldexp(num, power);
3808 #if _MSVCR_VER>=120
3810 /*********************************************************************
3811 * remainder (MSVCR120.@)
3813 double CDECL remainder(double x, double y)
3815 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3816 if(!isfinite(x)) *_errno() = EDOM;
3817 if(isnan(y) || y==0.0) *_errno() = EDOM;
3818 return unix_funcs->remainder( x, y );
3821 /*********************************************************************
3822 * remainderf (MSVCR120.@)
3824 float CDECL remainderf(float x, float y)
3826 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3827 if(!isfinite(x)) *_errno() = EDOM;
3828 if(isnan(y) || y==0.0f) *_errno() = EDOM;
3829 return unix_funcs->remainderf( x, y );
3832 /*********************************************************************
3833 * remquo (MSVCR120.@)
3835 double CDECL remquo(double x, double y, int *quo)
3837 if(!isfinite(x)) *_errno() = EDOM;
3838 if(isnan(y) || y==0.0) *_errno() = EDOM;
3839 return unix_funcs->remquo( x, y, quo );
3842 /*********************************************************************
3843 * remquof (MSVCR120.@)
3845 float CDECL remquof(float x, float y, int *quo)
3847 if(!isfinite(x)) *_errno() = EDOM;
3848 if(isnan(y) || y==0.0f) *_errno() = EDOM;
3849 return unix_funcs->remquof( x, y, quo );
3852 /*********************************************************************
3853 * lgamma (MSVCR120.@)
3855 double CDECL lgamma(double x)
3857 return unix_funcs->lgamma( x );
3860 /*********************************************************************
3861 * lgammaf (MSVCR120.@)
3863 float CDECL lgammaf(float x)
3865 return unix_funcs->lgammaf( x );
3868 /*********************************************************************
3869 * tgamma (MSVCR120.@)
3871 double CDECL tgamma(double x)
3873 return unix_funcs->tgamma( x );
3876 /*********************************************************************
3877 * tgammaf (MSVCR120.@)
3879 float CDECL tgammaf(float x)
3881 return unix_funcs->tgammaf( x );
3884 /*********************************************************************
3885 * nan (MSVCR120.@)
3887 double CDECL nan(const char *tagp)
3889 /* Windows ignores input (MSDN) */
3890 return NAN;
3893 /*********************************************************************
3894 * nanf (MSVCR120.@)
3896 float CDECL nanf(const char *tagp)
3898 return NAN;
3901 /*********************************************************************
3902 * _except1 (MSVCR120.@)
3903 * TODO:
3904 * - find meaning of ignored cw and operation bits
3905 * - unk parameter
3907 double CDECL _except1(DWORD fpe, _FP_OPERATION_CODE op, double arg, double res, DWORD cw, void *unk)
3909 ULONG_PTR exception_arg;
3910 DWORD exception = 0;
3911 fenv_t env;
3912 DWORD fpword = 0;
3913 WORD operation;
3915 TRACE("(%x %x %lf %lf %x %p)\n", fpe, op, arg, res, cw, unk);
3917 #ifdef _WIN64
3918 cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
3919 #endif
3920 operation = op << 5;
3921 exception_arg = (ULONG_PTR)&operation;
3923 fegetenv(&env);
3925 if (fpe & 0x1) { /* overflow */
3926 if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
3927 /* 32-bit version also sets SW_INEXACT here */
3928 env._Fe_stat |= FE_OVERFLOW;
3929 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
3930 res = signbit(res) ? -INFINITY : INFINITY;
3931 } else {
3932 exception = EXCEPTION_FLT_OVERFLOW;
3934 } else if (fpe & 0x2) { /* underflow */
3935 if ((fpe == 0x2 && (cw & 0x10)) || (fpe==0x12 && (cw & 0x30))) {
3936 env._Fe_stat |= FE_UNDERFLOW;
3937 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
3938 res = signbit(res) ? -0.0 : 0.0;
3939 } else {
3940 exception = EXCEPTION_FLT_UNDERFLOW;
3942 } else if (fpe & 0x4) { /* zerodivide */
3943 if ((fpe == 0x4 && (cw & 0x4)) || (fpe==0x14 && (cw & 0x24))) {
3944 env._Fe_stat |= FE_DIVBYZERO;
3945 if (fpe & 0x10) env._Fe_stat |= FE_INEXACT;
3946 } else {
3947 exception = EXCEPTION_FLT_DIVIDE_BY_ZERO;
3949 } else if (fpe & 0x8) { /* invalid */
3950 if (fpe == 0x8 && (cw & 0x1)) {
3951 env._Fe_stat |= FE_INVALID;
3952 } else {
3953 exception = EXCEPTION_FLT_INVALID_OPERATION;
3955 } else if (fpe & 0x10) { /* inexact */
3956 if (fpe == 0x10 && (cw & 0x20)) {
3957 env._Fe_stat |= FE_INEXACT;
3958 } else {
3959 exception = EXCEPTION_FLT_INEXACT_RESULT;
3963 if (exception)
3964 env._Fe_stat = 0;
3965 fesetenv(&env);
3966 if (exception)
3967 RaiseException(exception, 0, 1, &exception_arg);
3969 if (cw & 0x1) fpword |= _EM_INVALID;
3970 if (cw & 0x2) fpword |= _EM_DENORMAL;
3971 if (cw & 0x4) fpword |= _EM_ZERODIVIDE;
3972 if (cw & 0x8) fpword |= _EM_OVERFLOW;
3973 if (cw & 0x10) fpword |= _EM_UNDERFLOW;
3974 if (cw & 0x20) fpword |= _EM_INEXACT;
3975 switch (cw & 0xc00)
3977 case 0xc00: fpword |= _RC_UP|_RC_DOWN; break;
3978 case 0x800: fpword |= _RC_UP; break;
3979 case 0x400: fpword |= _RC_DOWN; break;
3981 switch (cw & 0x300)
3983 case 0x0: fpword |= _PC_24; break;
3984 case 0x200: fpword |= _PC_53; break;
3985 case 0x300: fpword |= _PC_64; break;
3987 if (cw & 0x1000) fpword |= _IC_AFFINE;
3988 _control87(fpword, 0xffffffff);
3990 return res;
3993 _Dcomplex* CDECL _Cbuild(_Dcomplex *ret, double r, double i)
3995 ret->_Val[0] = r;
3996 ret->_Val[1] = i;
3997 return ret;
4000 double CDECL MSVCR120_creal(_Dcomplex z)
4002 return z._Val[0];
4005 /*********************************************************************
4006 * ilogb (MSVCR120.@)
4008 * Copied from musl: src/math/ilogb.c
4010 int CDECL ilogb(double x)
4012 union { double f; UINT64 i; } u = { x };
4013 int e = u.i >> 52 & 0x7ff;
4015 if (!e)
4017 u.i <<= 12;
4018 if (u.i == 0) return FP_ILOGB0;
4019 /* subnormal x */
4020 for (e = -0x3ff; u.i >> 63 == 0; e--, u.i <<= 1);
4021 return e;
4023 if (e == 0x7ff) return u.i << 12 ? FP_ILOGBNAN : INT_MAX;
4024 return e - 0x3ff;
4027 /*********************************************************************
4028 * ilogbf (MSVCR120.@)
4030 * Copied from musl: src/math/ilogbf.c
4032 int CDECL ilogbf(float x)
4034 union { float f; UINT32 i; } u = { x };
4035 int e = u.i >> 23 & 0xff;
4037 if (!e)
4039 u.i <<= 9;
4040 if (u.i == 0) return FP_ILOGB0;
4041 /* subnormal x */
4042 for (e = -0x7f; u.i >> 31 == 0; e--, u.i <<= 1);
4043 return e;
4045 if (e == 0xff) return u.i << 9 ? FP_ILOGBNAN : INT_MAX;
4046 return e - 0x7f;
4048 #endif /* _MSVCR_VER>=120 */