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 * ====================================================
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
55 #define _DOMAIN 1 /* domain error in argument */
56 #define _SING 2 /* singularity */
57 #define _OVERFLOW 3 /* range overflow */
58 #define _UNDERFLOW 4 /* range underflow */
60 typedef int (CDECL
*MSVCRT_matherr_func
)(struct _exception
*);
61 typedef double LDOUBLE
; /* long double is just a double */
63 static MSVCRT_matherr_func MSVCRT_default_matherr_func
= NULL
;
65 static BOOL sse2_supported
;
66 static BOOL sse2_enabled
;
68 static const struct unix_funcs
*unix_funcs
;
70 void msvcrt_init_math( void *module
)
72 sse2_supported
= sse2_enabled
= IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE
);
73 __wine_init_unix_lib( module
, DLL_PROCESS_ATTACH
, NULL
, &unix_funcs
);
76 /* Copied from musl: src/internal/libm.h */
77 static inline float fp_barrierf(float x
)
83 /*********************************************************************
86 int CDECL
MSVCRT__matherr(struct _exception
*e
)
92 static double math_error(int type
, const char *name
, double arg1
, double arg2
, double retval
)
94 struct _exception exception
= {type
, (char *)name
, arg1
, arg2
, retval
};
96 TRACE("(%d, %s, %g, %g, %g)\n", type
, debugstr_a(name
), arg1
, arg2
, retval
);
98 if (MSVCRT_default_matherr_func
&& MSVCRT_default_matherr_func(&exception
))
99 return exception
.retval
;
111 /* don't set errno */
114 ERR("Unhandled math error!\n");
117 return exception
.retval
;
120 /*********************************************************************
121 * __setusermatherr (MSVCRT.@)
123 void CDECL
MSVCRT___setusermatherr(MSVCRT_matherr_func func
)
125 MSVCRT_default_matherr_func
= func
;
126 TRACE("new matherr handler %p\n", func
);
129 /*********************************************************************
130 * _set_SSE2_enable (MSVCRT.@)
132 int CDECL
MSVCRT__set_SSE2_enable(int flag
)
134 sse2_enabled
= flag
&& sse2_supported
;
140 /*********************************************************************
141 * _get_FMA3_enable (UCRTBASE.@)
143 int CDECL
MSVCRT__get_FMA3_enable(void)
151 /*********************************************************************
152 * _set_FMA3_enable (MSVCR120.@)
154 int CDECL
MSVCRT__set_FMA3_enable(int flag
)
156 FIXME("(%x) stub\n", flag
);
162 #if !defined(__i386__) || _MSVCR_VER>=120
164 /*********************************************************************
165 * _chgsignf (MSVCRT.@)
167 float CDECL
MSVCRT__chgsignf( float num
)
169 union { float f
; UINT32 i
; } u
= { num
};
174 /*********************************************************************
175 * _copysignf (MSVCRT.@)
177 * Copied from musl: src/math/copysignf.c
179 float CDECL
MSVCRT__copysignf( float x
, float y
)
181 union { float f
; UINT32 i
; } ux
= { x
}, uy
= { y
};
183 ux
.i
|= uy
.i
& 0x80000000;
187 /*********************************************************************
188 * _nextafterf (MSVCRT.@)
190 float CDECL
MSVCRT__nextafterf( float num
, float next
)
192 if (!isfinite(num
) || !isfinite(next
)) *_errno() = EDOM
;
193 return unix_funcs
->nextafterf( num
, next
);
196 /*********************************************************************
199 float CDECL
MSVCRT__logbf( float num
)
201 float ret
= unix_funcs
->logbf(num
);
202 if (isnan(num
)) return math_error(_DOMAIN
, "_logbf", num
, 0, ret
);
203 if (!num
) return math_error(_SING
, "_logbf", num
, 0, ret
);
209 /*********************************************************************
210 * _fpclassf (MSVCRT.@)
212 int CDECL
MSVCRT__fpclassf( float num
)
214 union { float f
; UINT32 i
; } u
= { num
};
215 int e
= u
.i
>> 23 & 0xff;
221 if (u
.i
<< 1) return s
? _FPCLASS_ND
: _FPCLASS_PD
;
222 return s
? _FPCLASS_NZ
: _FPCLASS_PZ
;
224 if (u
.i
<< 9) return ((u
.i
>> 22) & 1) ? _FPCLASS_QNAN
: _FPCLASS_SNAN
;
225 return s
? _FPCLASS_NINF
: _FPCLASS_PINF
;
227 return s
? _FPCLASS_NN
: _FPCLASS_PN
;
231 /*********************************************************************
232 * _finitef (MSVCRT.@)
234 int CDECL
MSVCRT__finitef( float num
)
236 union { float f
; UINT32 i
; } u
= { num
};
237 return (u
.i
& 0x7fffffff) < 0x7f800000;
240 /*********************************************************************
243 int CDECL
MSVCRT__isnanf( float num
)
245 union { float f
; UINT32 i
; } u
= { num
};
246 return (u
.i
& 0x7fffffff) > 0x7f800000;
249 /*********************************************************************
250 * MSVCRT_acosf (MSVCRT.@)
252 * Copied from musl: src/math/acosf.c
254 static float acosf_R(float z
)
256 static const float pS0
= 1.6666586697e-01,
257 pS1
= -4.2743422091e-02,
258 pS2
= -8.6563630030e-03,
259 qS1
= -7.0662963390e-01;
262 p
= z
* (pS0
+ z
* (pS1
+ z
* pS2
));
267 float CDECL
MSVCRT_acosf( float x
)
269 static const float pio2_hi
= 1.5707962513e+00,
270 pio2_lo
= 7.5497894159e-08;
272 float z
, w
, s
, c
, df
;
275 hx
= *(unsigned int*)&x
;
276 ix
= hx
& 0x7fffffff;
277 /* |x| >= 1 or nan */
278 if (ix
>= 0x3f800000) {
279 if (ix
== 0x3f800000) {
281 return 2 * pio2_lo
+ 2 * pio2_hi
+ 7.5231638453e-37;
284 if (isnan(x
)) return x
;
285 return math_error(_DOMAIN
, "acosf", x
, 0, 0 / (x
- x
));
288 if (ix
< 0x3f000000) {
289 if (ix
<= 0x32800000) /* |x| < 2**-26 */
290 return pio2_lo
+ pio2_hi
+ 7.5231638453e-37;
291 return pio2_hi
- (x
- (pio2_lo
- x
* acosf_R(x
* x
)));
297 w
= acosf_R(z
) * s
- pio2_lo
;
298 return 2 * (pio2_hi
- (s
+ w
));
303 hx
= *(unsigned int*)&s
& 0xfffff000;
305 c
= (z
- df
* df
) / (s
+ df
);
306 w
= acosf_R(z
) * s
+ c
;
310 /*********************************************************************
311 * MSVCRT_asinf (MSVCRT.@)
313 * Copied from musl: src/math/asinf.c
315 static float asinf_R(float z
)
317 /* coefficients for R(x^2) */
318 static const float pS0
= 1.6666586697e-01,
319 pS1
= -4.2743422091e-02,
320 pS2
= -8.6563630030e-03,
321 qS1
= -7.0662963390e-01;
324 p
= z
* (pS0
+ z
* (pS1
+ z
* pS2
));
329 float CDECL
MSVCRT_asinf( float x
)
331 static const double pio2
= 1.570796326794896558e+00;
337 hx
= *(unsigned int*)&x
;
338 ix
= hx
& 0x7fffffff;
339 if (ix
>= 0x3f800000) { /* |x| >= 1 */
340 if (ix
== 0x3f800000) /* |x| == 1 */
341 return x
* pio2
+ 7.5231638453e-37; /* asin(+-1) = +-pi/2 with inexact */
342 if (isnan(x
)) return x
;
343 return math_error(_DOMAIN
, "asinf", x
, 0, 0 / (x
- x
));
345 if (ix
< 0x3f000000) { /* |x| < 0.5 */
346 /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
347 if (ix
< 0x39800000 && ix
>= 0x00800000)
349 return x
+ x
* asinf_R(x
* x
);
352 z
= (1 - fabsf(x
)) * 0.5f
;
354 x
= pio2
- 2 * (s
+ s
* asinf_R(z
));
360 /*********************************************************************
361 * MSVCRT_atanf (MSVCRT.@)
363 * Copied from musl: src/math/atanf.c
365 float CDECL
MSVCRT_atanf( float x
)
367 static const float atanhi
[] = {
373 static const float atanlo
[] = {
379 static const float aT
[] = {
388 unsigned int ix
, sign
;
392 if (isnan(x
)) return math_error(_DOMAIN
, "atanf", x
, 0, x
);
395 ix
= *(unsigned int*)&x
;
398 if (ix
>= 0x4c800000) { /* if |x| >= 2**26 */
401 z
= atanhi
[3] + 7.5231638453e-37;
402 return sign
? -z
: z
;
404 if (ix
< 0x3ee00000) { /* |x| < 0.4375 */
405 if (ix
< 0x39800000) { /* |x| < 2**-12 */
407 /* raise underflow for subnormal x */
414 if (ix
< 0x3f980000) { /* |x| < 1.1875 */
415 if (ix
< 0x3f300000) { /* 7/16 <= |x| < 11/16 */
417 x
= (2.0f
* x
- 1.0f
) / (2.0f
+ x
);
418 } else { /* 11/16 <= |x| < 19/16 */
420 x
= (x
- 1.0f
) / (x
+ 1.0f
);
423 if (ix
< 0x401c0000) { /* |x| < 2.4375 */
425 x
= (x
- 1.5f
) / (1.0f
+ 1.5f
* x
);
426 } else { /* 2.4375 <= |x| < 2**26 */
432 /* end of argument reduction */
435 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
436 s1
= z
* (aT
[0] + w
* (aT
[2] + w
* aT
[4]));
437 s2
= w
* (aT
[1] + w
* aT
[3]);
439 return x
- x
* (s1
+ s2
);
440 z
= atanhi
[id
] - ((x
* (s1
+ s2
) - atanlo
[id
]) - x
);
441 return sign
? -z
: z
;
444 /*********************************************************************
445 * MSVCRT_atan2f (MSVCRT.@)
447 * Copied from musl: src/math/atan2f.c
449 float CDECL
MSVCRT_atan2f( float y
, float x
)
451 static const float pi
= 3.1415927410e+00,
452 pi_lo
= -8.7422776573e-08;
455 unsigned int m
, ix
, iy
;
457 if (isnan(x
) || isnan(y
))
459 ix
= *(unsigned int*)&x
;
460 iy
= *(unsigned int*)&y
;
461 if (ix
== 0x3f800000) /* x=1.0 */
462 return MSVCRT_atanf(y
);
463 m
= ((iy
>> 31) & 1) | ((ix
>> 30) & 2); /* 2*sign(x)+sign(y) */
471 case 1: return y
; /* atan(+-0,+anything)=+-0 */
472 case 2: return pi
; /* atan(+0,-anything) = pi */
473 case 3: return -pi
; /* atan(-0,-anything) =-pi */
478 return m
& 1 ? -pi
/ 2 : pi
/ 2;
480 if (ix
== 0x7f800000) {
481 if (iy
== 0x7f800000) {
483 case 0: return pi
/ 4; /* atan(+INF,+INF) */
484 case 1: return -pi
/ 4; /* atan(-INF,+INF) */
485 case 2: return 3 * pi
/ 4; /*atan(+INF,-INF)*/
486 case 3: return -3 * pi
/ 4; /*atan(-INF,-INF)*/
490 case 0: return 0.0f
; /* atan(+...,+INF) */
491 case 1: return -0.0f
; /* atan(-...,+INF) */
492 case 2: return pi
; /* atan(+...,-INF) */
493 case 3: return -pi
; /* atan(-...,-INF) */
498 if (ix
+ (26 << 23) < iy
|| iy
== 0x7f800000)
499 return m
& 1 ? -pi
/ 2 : pi
/ 2;
501 /* z = atan(|y/x|) with correct underflow */
502 if ((m
& 2) && iy
+ (26 << 23) < ix
) /*|y/x| < 0x1p-26, x < 0 */
505 z
= MSVCRT_atanf(fabsf(y
/ x
));
507 case 0: return z
; /* atan(+,+) */
508 case 1: return -z
; /* atan(-,+) */
509 case 2: return pi
- (z
- pi_lo
); /* atan(+,-) */
510 default: /* case 3 */
511 return (z
- pi_lo
) - pi
; /* atan(-,-) */
515 /*********************************************************************
516 * MSVCRT_cosf (MSVCRT.@)
518 float CDECL
MSVCRT_cosf( float x
)
520 float ret
= unix_funcs
->cosf( x
);
521 if (!isfinite(x
)) return math_error(_DOMAIN
, "cosf", x
, 0, ret
);
525 /*********************************************************************
526 * MSVCRT_coshf (MSVCRT.@)
528 float CDECL
MSVCRT_coshf( float x
)
530 float ret
= unix_funcs
->coshf( x
);
531 if (isnan(x
)) return math_error(_DOMAIN
, "coshf", x
, 0, ret
);
535 /*********************************************************************
536 * MSVCRT_expf (MSVCRT.@)
538 float CDECL
MSVCRT_expf( float x
)
540 float ret
= unix_funcs
->expf( x
);
541 if (isnan(x
)) return math_error(_DOMAIN
, "expf", x
, 0, ret
);
542 if (isfinite(x
) && !ret
) return math_error(_UNDERFLOW
, "expf", x
, 0, ret
);
543 if (isfinite(x
) && !isfinite(ret
)) return math_error(_OVERFLOW
, "expf", x
, 0, ret
);
547 /*********************************************************************
548 * MSVCRT_fmodf (MSVCRT.@)
550 float CDECL
MSVCRT_fmodf( float x
, float y
)
552 float ret
= unix_funcs
->fmodf( x
, y
);
553 if (!isfinite(x
) || !isfinite(y
)) return math_error(_DOMAIN
, "fmodf", x
, 0, ret
);
557 /*********************************************************************
558 * MSVCRT_logf (MSVCRT.@)
560 float CDECL
MSVCRT_logf( float x
)
562 float ret
= unix_funcs
->logf( x
);
563 if (x
< 0.0) return math_error(_DOMAIN
, "logf", x
, 0, ret
);
564 if (x
== 0.0) return math_error(_SING
, "logf", x
, 0, ret
);
568 /*********************************************************************
569 * MSVCRT_log10f (MSVCRT.@)
571 float CDECL
MSVCRT_log10f( float x
)
573 float ret
= unix_funcs
->log10f( x
);
574 if (x
< 0.0) return math_error(_DOMAIN
, "log10f", x
, 0, ret
);
575 if (x
== 0.0) return math_error(_SING
, "log10f", x
, 0, ret
);
579 /*********************************************************************
580 * MSVCRT_powf (MSVCRT.@)
582 float CDECL
MSVCRT_powf( float x
, float y
)
584 float z
= unix_funcs
->powf(x
,y
);
585 if (x
< 0 && y
!= MSVCRT_floorf(y
)) return math_error(_DOMAIN
, "powf", x
, y
, z
);
586 if (!x
&& isfinite(y
) && y
< 0) return math_error(_SING
, "powf", x
, y
, z
);
587 if (isfinite(x
) && isfinite(y
) && !isfinite(z
)) return math_error(_OVERFLOW
, "powf", x
, y
, z
);
588 if (x
&& isfinite(x
) && isfinite(y
) && !z
) return math_error(_UNDERFLOW
, "powf", x
, y
, z
);
592 /*********************************************************************
593 * MSVCRT_sinf (MSVCRT.@)
595 float CDECL
MSVCRT_sinf( float x
)
597 float ret
= unix_funcs
->sinf( x
);
598 if (!isfinite(x
)) return math_error(_DOMAIN
, "sinf", x
, 0, ret
);
602 /*********************************************************************
603 * MSVCRT_sinhf (MSVCRT.@)
605 float CDECL
MSVCRT_sinhf( float x
)
607 float ret
= unix_funcs
->sinhf( x
);
608 if (isnan(x
)) return math_error(_DOMAIN
, "sinhf", x
, 0, ret
);
612 /*********************************************************************
613 * MSVCRT_sqrtf (MSVCRT.@)
615 * Copied from musl: src/math/sqrtf.c
617 float CDECL
MSVCRT_sqrtf( float x
)
619 static const float tiny
= 1.0e-30;
622 int sign
= 0x80000000;
628 /* take care of Inf and NaN */
629 if ((ix
& 0x7f800000) == 0x7f800000 && (ix
== 0x7f800000 || ix
& 0x7fffff))
632 /* take care of zero */
634 if ((ix
& ~sign
) == 0)
635 return x
; /* sqrt(+-0) = +-0 */
636 return math_error(_DOMAIN
, "sqrtf", x
, 0, (x
- x
) / (x
- x
)); /* sqrt(-ve) = sNaN */
640 if (m
== 0) { /* subnormal x */
641 for (i
= 0; (ix
& 0x00800000) == 0; i
++)
645 m
-= 127; /* unbias exponent */
646 ix
= (ix
& 0x007fffff) | 0x00800000;
647 if (m
& 1) /* odd m, double x to make it even */
649 m
>>= 1; /* m = [m/2] */
651 /* generate sqrt(x) bit by bit */
653 q
= s
= 0; /* q = sqrt(x) */
654 r
= 0x01000000; /* r = moving bit from right to left */
667 /* use floating add to find out rounding direction */
669 z
= 1.0f
- tiny
; /* raise inexact flag */
678 ix
= (q
>> 1) + 0x3f000000;
679 r
= ix
+ ((unsigned int)m
<< 23);
684 /*********************************************************************
685 * MSVCRT_tanf (MSVCRT.@)
687 float CDECL
MSVCRT_tanf( float x
)
689 float ret
= unix_funcs
->tanf(x
);
690 if (!isfinite(x
)) return math_error(_DOMAIN
, "tanf", x
, 0, ret
);
694 /*********************************************************************
695 * MSVCRT_tanhf (MSVCRT.@)
697 float CDECL
MSVCRT_tanhf( float x
)
699 float ret
= unix_funcs
->tanhf(x
);
700 if (!isfinite(x
)) return math_error(_DOMAIN
, "tanhf", x
, 0, ret
);
704 /*********************************************************************
707 float CDECL
MSVCRT_ceilf( float x
)
709 return unix_funcs
->ceilf(x
);
712 /*********************************************************************
715 * Copied from musl: src/math/fabsf.c
717 float CDECL
MSVCRT_fabsf( float x
)
719 union { float f
; UINT32 i
; } u
= { x
};
724 /*********************************************************************
727 float CDECL
MSVCRT_floorf( float x
)
729 return unix_funcs
->floorf(x
);
732 /*********************************************************************
735 float CDECL
MSVCRT_frexpf( float x
, int *exp
)
737 return unix_funcs
->frexpf( x
, exp
);
740 /*********************************************************************
743 float CDECL
MSVCRT_modff( float x
, float *iptr
)
745 return unix_funcs
->modff( x
, iptr
);
748 /*********************************************************************
749 * MSVCRT_acos (MSVCRT.@)
751 * Copied from musl: src/math/acos.c
753 static double acos_R(double z
)
755 static const double pS0
= 1.66666666666666657415e-01,
756 pS1
= -3.25565818622400915405e-01,
757 pS2
= 2.01212532134862925881e-01,
758 pS3
= -4.00555345006794114027e-02,
759 pS4
= 7.91534994289814532176e-04,
760 pS5
= 3.47933107596021167570e-05,
761 qS1
= -2.40339491173441421878e+00,
762 qS2
= 2.02094576023350569471e+00,
763 qS3
= -6.88283971605453293030e-01,
764 qS4
= 7.70381505559019352791e-02;
767 p
= z
* (pS0
+ z
* (pS1
+ z
* (pS2
+ z
* (pS3
+ z
* (pS4
+ z
* pS5
)))));
768 q
= 1.0 + z
* (qS1
+ z
* (qS2
+ z
* (qS3
+ z
* qS4
)));
772 double CDECL
MSVCRT_acos( double x
)
774 static const double pio2_hi
= 1.57079632679489655800e+00,
775 pio2_lo
= 6.12323399573676603587e-17;
777 double z
, w
, s
, c
, df
;
781 hx
= *(ULONGLONG
*)&x
>> 32;
782 ix
= hx
& 0x7fffffff;
783 /* |x| >= 1 or nan */
784 if (ix
>= 0x3ff00000) {
787 lx
= *(ULONGLONG
*)&x
;
788 if (((ix
- 0x3ff00000) | lx
) == 0) {
789 /* acos(1)=0, acos(-1)=pi */
791 return 2 * pio2_hi
+ 7.5231638452626401e-37;
794 if (isnan(x
)) return x
;
795 return math_error(_DOMAIN
, "acos", x
, 0, 0 / (x
- x
));
798 if (ix
< 0x3fe00000) {
799 if (ix
<= 0x3c600000) /* |x| < 2**-57 */
800 return pio2_hi
+ 7.5231638452626401e-37;
801 return pio2_hi
- (x
- (pio2_lo
- x
* acos_R(x
* x
)));
807 w
= acos_R(z
) * s
- pio2_lo
;
808 return 2 * (pio2_hi
- (s
+ w
));
814 llx
= (*(ULONGLONG
*)&df
>> 32) << 32;
816 c
= (z
- df
* df
) / (s
+ df
);
817 w
= acos_R(z
) * s
+ c
;
821 /*********************************************************************
822 * MSVCRT_asin (MSVCRT.@)
824 * Copied from musl: src/math/asin.c
826 static double asin_R(double z
)
828 /* coefficients for R(x^2) */
829 static const double pS0
= 1.66666666666666657415e-01,
830 pS1
= -3.25565818622400915405e-01,
831 pS2
= 2.01212532134862925881e-01,
832 pS3
= -4.00555345006794114027e-02,
833 pS4
= 7.91534994289814532176e-04,
834 pS5
= 3.47933107596021167570e-05,
835 qS1
= -2.40339491173441421878e+00,
836 qS2
= 2.02094576023350569471e+00,
837 qS3
= -6.88283971605453293030e-01,
838 qS4
= 7.70381505559019352791e-02;
841 p
= z
* (pS0
+ z
* (pS1
+ z
* (pS2
+ z
* (pS3
+ z
* (pS4
+ z
* pS5
)))));
842 q
= 1.0 + z
* (qS1
+ z
* (qS2
+ z
* (qS3
+ z
* qS4
)));
846 double CDECL
MSVCRT_asin( double x
)
848 static const double pio2_hi
= 1.57079632679489655800e+00,
849 pio2_lo
= 6.12323399573676603587e-17;
855 hx
= *(ULONGLONG
*)&x
>> 32;
856 ix
= hx
& 0x7fffffff;
857 /* |x| >= 1 or nan */
858 if (ix
>= 0x3ff00000) {
860 lx
= *(ULONGLONG
*)&x
;
861 if (((ix
- 0x3ff00000) | lx
) == 0)
862 /* asin(1) = +-pi/2 with inexact */
863 return x
* pio2_hi
+ 7.5231638452626401e-37;
864 if (isnan(x
)) return x
;
865 return math_error(_DOMAIN
, "asin", x
, 0, 0 / (x
- x
));
868 if (ix
< 0x3fe00000) {
869 /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */
870 if (ix
< 0x3e500000 && ix
>= 0x00100000)
872 return x
+ x
* asin_R(x
* x
);
875 z
= (1 - fabs(x
)) * 0.5;
878 if (ix
>= 0x3fef3333) { /* if |x| > 0.975 */
879 x
= pio2_hi
- (2 * (s
+ s
* r
) - pio2_lo
);
884 llx
= (*(ULONGLONG
*)&f
>> 32) << 32;
886 c
= (z
- f
* f
) / (s
+ f
);
887 x
= 0.5 * pio2_hi
- (2 * s
* r
- (pio2_lo
- 2 * c
) - (0.5 * pio2_hi
- 2 * f
));
894 /*********************************************************************
895 * MSVCRT_atan (MSVCRT.@)
897 * Copied from musl: src/math/atan.c
899 double CDECL
MSVCRT_atan( double x
)
901 static const double atanhi
[] = {
902 4.63647609000806093515e-01,
903 7.85398163397448278999e-01,
904 9.82793723247329054082e-01,
905 1.57079632679489655800e+00,
907 static const double atanlo
[] = {
908 2.26987774529616870924e-17,
909 3.06161699786838301793e-17,
910 1.39033110312309984516e-17,
911 6.12323399573676603587e-17,
913 static const double aT
[] = {
914 3.33333333333329318027e-01,
915 -1.99999999998764832476e-01,
916 1.42857142725034663711e-01,
917 -1.11111104054623557880e-01,
918 9.09088713343650656196e-02,
919 -7.69187620504482999495e-02,
920 6.66107313738753120669e-02,
921 -5.83357013379057348645e-02,
922 4.97687799461593236017e-02,
923 -3.65315727442169155270e-02,
924 1.62858201153657823623e-02,
928 unsigned int ix
, sign
;
932 if (isnan(x
)) return math_error(_DOMAIN
, "atan", x
, 0, x
);
935 ix
= *(ULONGLONG
*)&x
>> 32;
938 if (ix
>= 0x44100000) { /* if |x| >= 2^66 */
941 z
= atanhi
[3] + 7.5231638452626401e-37;
942 return sign
? -z
: z
;
944 if (ix
< 0x3fdc0000) { /* |x| < 0.4375 */
945 if (ix
< 0x3e400000) { /* |x| < 2^-27 */
947 /* raise underflow for subnormal x */
948 fp_barrierf((float)x
);
954 if (ix
< 0x3ff30000) { /* |x| < 1.1875 */
955 if (ix
< 0x3fe60000) { /* 7/16 <= |x| < 11/16 */
957 x
= (2.0 * x
- 1.0) / (2.0 + x
);
958 } else { /* 11/16 <= |x| < 19/16 */
960 x
= (x
- 1.0) / (x
+ 1.0);
963 if (ix
< 0x40038000) { /* |x| < 2.4375 */
965 x
= (x
- 1.5) / (1.0 + 1.5 * x
);
966 } else { /* 2.4375 <= |x| < 2^66 */
972 /* end of argument reduction */
975 /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
976 s1
= z
* (aT
[0] + w
* (aT
[2] + w
* (aT
[4] + w
* (aT
[6] + w
* (aT
[8] + w
* aT
[10])))));
977 s2
= w
* (aT
[1] + w
* (aT
[3] + w
* (aT
[5] + w
* (aT
[7] + w
* aT
[9]))));
979 return x
- x
* (s1
+ s2
);
980 z
= atanhi
[id
] - (x
* (s1
+ s2
) - atanlo
[id
] - x
);
981 return sign
? -z
: z
;
984 /*********************************************************************
985 * MSVCRT_atan2 (MSVCRT.@)
987 * Copied from musl: src/math/atan2.c
989 double CDECL
MSVCRT_atan2( double y
, double x
)
991 static const double pi
= 3.1415926535897931160E+00,
992 pi_lo
= 1.2246467991473531772E-16;
995 unsigned int m
, lx
, ly
, ix
, iy
;
997 if (isnan(x
) || isnan(y
))
999 ix
= *(ULONGLONG
*)&x
>> 32;
1000 lx
= *(ULONGLONG
*)&x
;
1001 iy
= *(ULONGLONG
*)&y
>> 32;
1002 ly
= *(ULONGLONG
*)&y
;
1003 if (((ix
- 0x3ff00000) | lx
) == 0) /* x = 1.0 */
1004 return MSVCRT_atan(y
);
1005 m
= ((iy
>> 31) & 1) | ((ix
>> 30) & 2); /* 2*sign(x)+sign(y) */
1006 ix
= ix
& 0x7fffffff;
1007 iy
= iy
& 0x7fffffff;
1010 if ((iy
| ly
) == 0) {
1013 case 1: return y
; /* atan(+-0,+anything)=+-0 */
1014 case 2: return pi
; /* atan(+0,-anything) = pi */
1015 case 3: return -pi
; /* atan(-0,-anything) =-pi */
1020 return m
& 1 ? -pi
/ 2 : pi
/ 2;
1022 if (ix
== 0x7ff00000) {
1023 if (iy
== 0x7ff00000) {
1025 case 0: return pi
/ 4; /* atan(+INF,+INF) */
1026 case 1: return -pi
/ 4; /* atan(-INF,+INF) */
1027 case 2: return 3 * pi
/ 4; /* atan(+INF,-INF) */
1028 case 3: return -3 * pi
/ 4; /* atan(-INF,-INF) */
1032 case 0: return 0.0; /* atan(+...,+INF) */
1033 case 1: return -0.0; /* atan(-...,+INF) */
1034 case 2: return pi
; /* atan(+...,-INF) */
1035 case 3: return -pi
; /* atan(-...,-INF) */
1039 /* |y/x| > 0x1p64 */
1040 if (ix
+ (64 << 20) < iy
|| iy
== 0x7ff00000)
1041 return m
& 1 ? -pi
/ 2 : pi
/ 2;
1043 /* z = atan(|y/x|) without spurious underflow */
1044 if ((m
& 2) && iy
+ (64 << 20) < ix
) /* |y/x| < 0x1p-64, x<0 */
1047 z
= MSVCRT_atan(fabs(y
/ x
));
1049 case 0: return z
; /* atan(+,+) */
1050 case 1: return -z
; /* atan(-,+) */
1051 case 2: return pi
- (z
- pi_lo
); /* atan(+,-) */
1052 default: /* case 3 */
1053 return (z
- pi_lo
) - pi
; /* atan(-,-) */
1057 /*********************************************************************
1058 * MSVCRT_cos (MSVCRT.@)
1060 double CDECL
MSVCRT_cos( double x
)
1062 double ret
= unix_funcs
->cos( x
);
1063 if (!isfinite(x
)) return math_error(_DOMAIN
, "cos", x
, 0, ret
);
1067 /*********************************************************************
1068 * MSVCRT_cosh (MSVCRT.@)
1070 double CDECL
MSVCRT_cosh( double x
)
1072 double ret
= unix_funcs
->cosh( x
);
1073 if (isnan(x
)) return math_error(_DOMAIN
, "cosh", x
, 0, ret
);
1077 /*********************************************************************
1078 * MSVCRT_exp (MSVCRT.@)
1080 double CDECL
MSVCRT_exp( double x
)
1082 double ret
= unix_funcs
->exp( x
);
1083 if (isnan(x
)) return math_error(_DOMAIN
, "exp", x
, 0, ret
);
1084 if (isfinite(x
) && !ret
) return math_error(_UNDERFLOW
, "exp", x
, 0, ret
);
1085 if (isfinite(x
) && !isfinite(ret
)) return math_error(_OVERFLOW
, "exp", x
, 0, ret
);
1089 /*********************************************************************
1090 * MSVCRT_fmod (MSVCRT.@)
1092 double CDECL
MSVCRT_fmod( double x
, double y
)
1094 double ret
= unix_funcs
->fmod( x
, y
);
1095 if (!isfinite(x
) || !isfinite(y
)) return math_error(_DOMAIN
, "fmod", x
, y
, ret
);
1099 /*********************************************************************
1100 * MSVCRT_log (MSVCRT.@)
1102 double CDECL
MSVCRT_log( double x
)
1104 double ret
= unix_funcs
->log( x
);
1105 if (x
< 0.0) return math_error(_DOMAIN
, "log", x
, 0, ret
);
1106 if (x
== 0.0) return math_error(_SING
, "log", x
, 0, ret
);
1110 /*********************************************************************
1111 * MSVCRT_log10 (MSVCRT.@)
1113 double CDECL
MSVCRT_log10( double x
)
1115 double ret
= unix_funcs
->log10( x
);
1116 if (x
< 0.0) return math_error(_DOMAIN
, "log10", x
, 0, ret
);
1117 if (x
== 0.0) return math_error(_SING
, "log10", x
, 0, ret
);
1121 /*********************************************************************
1122 * MSVCRT_pow (MSVCRT.@)
1124 double CDECL
MSVCRT_pow( double x
, double y
)
1126 double z
= unix_funcs
->pow(x
,y
);
1127 if (x
< 0 && y
!= MSVCRT_floor(y
))
1128 return math_error(_DOMAIN
, "pow", x
, y
, z
);
1129 if (!x
&& isfinite(y
) && y
< 0)
1130 return math_error(_SING
, "pow", x
, y
, z
);
1131 if (isfinite(x
) && isfinite(y
) && !isfinite(z
))
1132 return math_error(_OVERFLOW
, "pow", x
, y
, z
);
1133 if (x
&& isfinite(x
) && isfinite(y
) && !z
)
1134 return math_error(_UNDERFLOW
, "pow", x
, y
, z
);
1138 /*********************************************************************
1139 * MSVCRT_sin (MSVCRT.@)
1141 double CDECL
MSVCRT_sin( double x
)
1143 double ret
= unix_funcs
->sin( x
);
1144 if (!isfinite(x
)) return math_error(_DOMAIN
, "sin", x
, 0, ret
);
1148 /*********************************************************************
1149 * MSVCRT_sinh (MSVCRT.@)
1151 double CDECL
MSVCRT_sinh( double x
)
1153 double ret
= unix_funcs
->sinh( x
);
1154 if (isnan(x
)) return math_error(_DOMAIN
, "sinh", x
, 0, ret
);
1158 /*********************************************************************
1159 * MSVCRT_sqrt (MSVCRT.@)
1161 * Copied from musl: src/math/sqrt.c
1163 double CDECL
MSVCRT_sqrt( double x
)
1165 static const double tiny
= 1.0e-300;
1168 int sign
= 0x80000000;
1170 unsigned int r
,t1
,s1
,ix1
,q1
;
1173 ix
= *(ULONGLONG
*)&x
;
1177 /* take care of Inf and NaN */
1178 if (isnan(x
) || (isinf(x
) && x
> 0))
1181 /* take care of zero */
1183 if (((ix0
& ~sign
) | ix1
) == 0)
1184 return x
; /* sqrt(+-0) = +-0 */
1186 return math_error(_DOMAIN
, "sqrt", x
, 0, (x
- x
) / (x
- x
));
1190 if (m
== 0) { /* subnormal x */
1196 for (i
=0; (ix0
& 0x00100000) == 0; i
++)
1199 ix0
|= ix1
>> (32 - i
);
1202 m
-= 1023; /* unbias exponent */
1203 ix0
= (ix0
& 0x000fffff) | 0x00100000;
1204 if (m
& 1) { /* odd m, double x to make it even */
1205 ix0
+= ix0
+ ((ix1
& sign
) >> 31);
1208 m
>>= 1; /* m = [m/2] */
1210 /* generate sqrt(x) bit by bit */
1211 ix0
+= ix0
+ ((ix1
& sign
) >> 31);
1213 q
= q1
= s0
= s1
= 0; /* [q,q1] = sqrt(x) */
1214 r
= 0x00200000; /* r = moving bit from right to left */
1223 ix0
+= ix0
+ ((ix1
& sign
) >> 31);
1232 if (t
< ix0
|| (t
== ix0
&& t1
<= ix1
)) {
1234 if ((t1
&sign
) == sign
&& (s1
& sign
) == 0)
1242 ix0
+= ix0
+ ((ix1
& sign
) >> 31);
1247 /* use floating add to find out rounding direction */
1248 if ((ix0
| ix1
) != 0) {
1249 z
= 1.0 - tiny
; /* raise inexact flag */
1252 if (q1
== (unsigned int)0xffffffff) {
1255 } else if (z
> 1.0) {
1256 if (q1
== (unsigned int)0xfffffffe)
1263 ix0
= (q
>> 1) + 0x3fe00000;
1267 ix
= ix0
+ ((unsigned int)m
<< 20);
1270 return *(double*)&ix
;
1273 /*********************************************************************
1274 * MSVCRT_tan (MSVCRT.@)
1276 double CDECL
MSVCRT_tan( double x
)
1278 double ret
= unix_funcs
->tan(x
);
1279 if (!isfinite(x
)) return math_error(_DOMAIN
, "tan", x
, 0, ret
);
1283 /*********************************************************************
1284 * MSVCRT_tanh (MSVCRT.@)
1286 double CDECL
MSVCRT_tanh( double x
)
1288 double ret
= unix_funcs
->tanh(x
);
1289 if (isnan(x
)) return math_error(_DOMAIN
, "tanh", x
, 0, ret
);
1294 #if defined(__GNUC__) && defined(__i386__)
1296 #define CREATE_FPU_FUNC1(name, call) \
1297 __ASM_GLOBAL_FUNC(name, \
1299 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1300 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1301 "movl %esp, %ebp\n\t" \
1302 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1303 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1304 "fstpl (%esp)\n\t" /* store function argument */ \
1306 "movl $1, %ecx\n\t" /* empty FPU stack */ \
1310 "and $0x4500, %ax\n\t" \
1311 "cmp $0x4100, %ax\n\t" \
1313 "fstpl (%esp,%ecx,8)\n\t" \
1318 "movl %ecx, -4(%ebp)\n\t" \
1319 "call " __ASM_NAME( #call ) "\n\t" \
1320 "movl -4(%ebp), %ecx\n\t" \
1321 "fstpl (%esp)\n\t" /* save result */ \
1322 "3:\n\t" /* restore FPU stack */ \
1324 "fldl (%esp,%ecx,8)\n\t" \
1325 "cmpl $0, %ecx\n\t" \
1328 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1329 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1332 #define CREATE_FPU_FUNC2(name, call) \
1333 __ASM_GLOBAL_FUNC(name, \
1335 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
1336 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
1337 "movl %esp, %ebp\n\t" \
1338 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
1339 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
1340 "fstpl 8(%esp)\n\t" /* store function argument */ \
1342 "fstpl (%esp)\n\t" \
1344 "movl $2, %ecx\n\t" /* empty FPU stack */ \
1348 "and $0x4500, %ax\n\t" \
1349 "cmp $0x4100, %ax\n\t" \
1351 "fstpl (%esp,%ecx,8)\n\t" \
1356 "movl %ecx, -4(%ebp)\n\t" \
1357 "call " __ASM_NAME( #call ) "\n\t" \
1358 "movl -4(%ebp), %ecx\n\t" \
1359 "fstpl 8(%esp)\n\t" /* save result */ \
1360 "3:\n\t" /* restore FPU stack */ \
1362 "fldl (%esp,%ecx,8)\n\t" \
1363 "cmpl $1, %ecx\n\t" \
1366 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
1367 __ASM_CFI(".cfi_same_value %ebp\n\t") \
1370 CREATE_FPU_FUNC1(_CIacos
, MSVCRT_acos
)
1371 CREATE_FPU_FUNC1(_CIasin
, MSVCRT_asin
)
1372 CREATE_FPU_FUNC1(_CIatan
, MSVCRT_atan
)
1373 CREATE_FPU_FUNC2(_CIatan2
, MSVCRT_atan2
)
1374 CREATE_FPU_FUNC1(_CIcos
, MSVCRT_cos
)
1375 CREATE_FPU_FUNC1(_CIcosh
, MSVCRT_cosh
)
1376 CREATE_FPU_FUNC1(_CIexp
, MSVCRT_exp
)
1377 CREATE_FPU_FUNC2(_CIfmod
, MSVCRT_fmod
)
1378 CREATE_FPU_FUNC1(_CIlog
, MSVCRT_log
)
1379 CREATE_FPU_FUNC1(_CIlog10
, MSVCRT_log10
)
1380 CREATE_FPU_FUNC2(_CIpow
, MSVCRT_pow
)
1381 CREATE_FPU_FUNC1(_CIsin
, MSVCRT_sin
)
1382 CREATE_FPU_FUNC1(_CIsinh
, MSVCRT_sinh
)
1383 CREATE_FPU_FUNC1(_CIsqrt
, MSVCRT_sqrt
)
1384 CREATE_FPU_FUNC1(_CItan
, MSVCRT_tan
)
1385 CREATE_FPU_FUNC1(_CItanh
, MSVCRT_tanh
)
1387 __ASM_GLOBAL_FUNC(MSVCRT__ftol
,
1389 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1390 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1391 "movl %esp, %ebp\n\t"
1392 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1393 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
1395 "mov (%esp), %ax\n\t"
1396 "or $0xc00, %ax\n\t"
1397 "mov %ax, 2(%esp)\n\t"
1399 "fistpq 4(%esp)\n\t"
1401 "movl 4(%esp), %eax\n\t"
1402 "movl 8(%esp), %edx\n\t"
1404 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1405 __ASM_CFI(".cfi_same_value %ebp\n\t")
1408 #endif /* defined(__GNUC__) && defined(__i386__) */
1410 /*********************************************************************
1411 * _fpclass (MSVCRT.@)
1413 int CDECL
MSVCRT__fpclass(double num
)
1415 union { double f
; UINT64 i
; } u
= { num
};
1416 int e
= u
.i
>> 52 & 0x7ff;
1422 if (u
.i
<< 1) return s
? _FPCLASS_ND
: _FPCLASS_PD
;
1423 return s
? _FPCLASS_NZ
: _FPCLASS_PZ
;
1425 if (u
.i
<< 12) return ((u
.i
>> 51) & 1) ? _FPCLASS_QNAN
: _FPCLASS_SNAN
;
1426 return s
? _FPCLASS_NINF
: _FPCLASS_PINF
;
1428 return s
? _FPCLASS_NN
: _FPCLASS_PN
;
1432 /*********************************************************************
1435 unsigned int CDECL
_rotl(unsigned int num
, int shift
)
1438 return (num
<< shift
) | (num
>> (32-shift
));
1441 /*********************************************************************
1444 __msvcrt_ulong CDECL
MSVCRT__lrotl(__msvcrt_ulong num
, int shift
)
1447 return (num
<< shift
) | (num
>> (32-shift
));
1450 /*********************************************************************
1453 __msvcrt_ulong CDECL
MSVCRT__lrotr(__msvcrt_ulong num
, int shift
)
1456 return (num
>> shift
) | (num
<< (32-shift
));
1459 /*********************************************************************
1462 unsigned int CDECL
_rotr(unsigned int num
, int shift
)
1465 return (num
>> shift
) | (num
<< (32-shift
));
1468 /*********************************************************************
1469 * _rotl64 (MSVCRT.@)
1471 unsigned __int64 CDECL
_rotl64(unsigned __int64 num
, int shift
)
1474 return (num
<< shift
) | (num
>> (64-shift
));
1477 /*********************************************************************
1478 * _rotr64 (MSVCRT.@)
1480 unsigned __int64 CDECL
_rotr64(unsigned __int64 num
, int shift
)
1483 return (num
>> shift
) | (num
<< (64-shift
));
1486 /*********************************************************************
1489 int CDECL
MSVCRT_abs( int n
)
1491 return n
>= 0 ? n
: -n
;
1494 /*********************************************************************
1497 __msvcrt_long CDECL
MSVCRT_labs( __msvcrt_long n
)
1499 return n
>= 0 ? n
: -n
;
1503 /*********************************************************************
1504 * llabs (MSVCR100.@)
1506 __int64 CDECL
MSVCRT_llabs( __int64 n
)
1508 return n
>= 0 ? n
: -n
;
1513 /*********************************************************************
1514 * imaxabs (MSVCR120.@)
1516 intmax_t CDECL
MSVCRT_imaxabs( intmax_t n
)
1518 return n
>= 0 ? n
: -n
;
1522 /*********************************************************************
1525 __int64 CDECL
_abs64( __int64 n
)
1527 return n
>= 0 ? n
: -n
;
1530 /*********************************************************************
1533 double CDECL
MSVCRT__logb(double num
)
1535 double ret
= unix_funcs
->logb(num
);
1536 if (isnan(num
)) return math_error(_DOMAIN
, "_logb", num
, 0, ret
);
1537 if (!num
) return math_error(_SING
, "_logb", num
, 0, ret
);
1541 /*********************************************************************
1544 double CDECL
_hypot(double x
, double y
)
1546 /* FIXME: errno handling */
1547 return unix_funcs
->hypot( x
, y
);
1550 /*********************************************************************
1551 * _hypotf (MSVCRT.@)
1553 float CDECL
MSVCRT__hypotf(float x
, float y
)
1555 /* FIXME: errno handling */
1556 return unix_funcs
->hypotf( x
, y
);
1559 /*********************************************************************
1562 double CDECL
MSVCRT_ceil( double x
)
1564 return unix_funcs
->ceil(x
);
1567 /*********************************************************************
1570 double CDECL
MSVCRT_floor( double x
)
1572 return unix_funcs
->floor(x
);
1575 /*********************************************************************
1578 double CDECL
MSVCRT_fma( double x
, double y
, double z
)
1580 double w
= unix_funcs
->fma(x
, y
, z
);
1581 if ((isinf(x
) && y
== 0) || (x
== 0 && isinf(y
))) *_errno() = EDOM
;
1582 else if (isinf(x
) && isinf(z
) && x
!= z
) *_errno() = EDOM
;
1583 else if (isinf(y
) && isinf(z
) && y
!= z
) *_errno() = EDOM
;
1587 /*********************************************************************
1590 float CDECL
MSVCRT_fmaf( float x
, float y
, float z
)
1592 float w
= unix_funcs
->fmaf(x
, y
, z
);
1593 if ((isinf(x
) && y
== 0) || (x
== 0 && isinf(y
))) *_errno() = EDOM
;
1594 else if (isinf(x
) && isinf(z
) && x
!= z
) *_errno() = EDOM
;
1595 else if (isinf(y
) && isinf(z
) && y
!= z
) *_errno() = EDOM
;
1599 /*********************************************************************
1602 * Copied from musl: src/math/fabsf.c
1604 double CDECL
MSVCRT_fabs( double x
)
1606 union { double f
; UINT64 i
; } u
= { x
};
1611 /*********************************************************************
1614 double CDECL
MSVCRT_frexp( double x
, int *exp
)
1616 return unix_funcs
->frexp( x
, exp
);
1619 /*********************************************************************
1622 double CDECL
MSVCRT_modf( double x
, double *iptr
)
1624 return unix_funcs
->modf( x
, iptr
);
1627 /**********************************************************************
1628 * _statusfp2 (MSVCRT.@)
1630 * Not exported by native msvcrt, added in msvcr80.
1632 #if defined(__i386__) || defined(__x86_64__)
1633 void CDECL
_statusfp2( unsigned int *x86_sw
, unsigned int *sse2_sw
)
1637 unsigned long fpword
;
1641 __asm__
__volatile__( "fstsw %0" : "=m" (fpword
) );
1643 if (fpword
& 0x1) flags
|= _SW_INVALID
;
1644 if (fpword
& 0x2) flags
|= _SW_DENORMAL
;
1645 if (fpword
& 0x4) flags
|= _SW_ZERODIVIDE
;
1646 if (fpword
& 0x8) flags
|= _SW_OVERFLOW
;
1647 if (fpword
& 0x10) flags
|= _SW_UNDERFLOW
;
1648 if (fpword
& 0x20) flags
|= _SW_INEXACT
;
1652 if (!sse2_sw
) return;
1656 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1658 if (fpword
& 0x1) flags
|= _SW_INVALID
;
1659 if (fpword
& 0x2) flags
|= _SW_DENORMAL
;
1660 if (fpword
& 0x4) flags
|= _SW_ZERODIVIDE
;
1661 if (fpword
& 0x8) flags
|= _SW_OVERFLOW
;
1662 if (fpword
& 0x10) flags
|= _SW_UNDERFLOW
;
1663 if (fpword
& 0x20) flags
|= _SW_INEXACT
;
1668 FIXME( "not implemented\n" );
1673 /**********************************************************************
1674 * _statusfp (MSVCRT.@)
1676 unsigned int CDECL
_statusfp(void)
1678 unsigned int flags
= 0;
1679 #if defined(__i386__) || defined(__x86_64__)
1680 unsigned int x86_sw
, sse2_sw
;
1682 _statusfp2( &x86_sw
, &sse2_sw
);
1683 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1684 flags
= x86_sw
| sse2_sw
;
1685 #elif defined(__aarch64__)
1688 __asm__
__volatile__( "mrs %0, fpsr" : "=r" (fpsr
) );
1689 if (fpsr
& 0x1) flags
|= _SW_INVALID
;
1690 if (fpsr
& 0x2) flags
|= _SW_ZERODIVIDE
;
1691 if (fpsr
& 0x4) flags
|= _SW_OVERFLOW
;
1692 if (fpsr
& 0x8) flags
|= _SW_UNDERFLOW
;
1693 if (fpsr
& 0x10) flags
|= _SW_INEXACT
;
1694 if (fpsr
& 0x80) flags
|= _SW_DENORMAL
;
1696 FIXME( "not implemented\n" );
1701 /*********************************************************************
1702 * _clearfp (MSVCRT.@)
1704 unsigned int CDECL
_clearfp(void)
1706 unsigned int flags
= 0;
1707 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1708 unsigned long fpword
;
1710 __asm__
__volatile__( "fnstsw %0; fnclex" : "=m" (fpword
) );
1711 if (fpword
& 0x1) flags
|= _SW_INVALID
;
1712 if (fpword
& 0x2) flags
|= _SW_DENORMAL
;
1713 if (fpword
& 0x4) flags
|= _SW_ZERODIVIDE
;
1714 if (fpword
& 0x8) flags
|= _SW_OVERFLOW
;
1715 if (fpword
& 0x10) flags
|= _SW_UNDERFLOW
;
1716 if (fpword
& 0x20) flags
|= _SW_INEXACT
;
1720 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1721 if (fpword
& 0x1) flags
|= _SW_INVALID
;
1722 if (fpword
& 0x2) flags
|= _SW_DENORMAL
;
1723 if (fpword
& 0x4) flags
|= _SW_ZERODIVIDE
;
1724 if (fpword
& 0x8) flags
|= _SW_OVERFLOW
;
1725 if (fpword
& 0x10) flags
|= _SW_UNDERFLOW
;
1726 if (fpword
& 0x20) flags
|= _SW_INEXACT
;
1728 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
1730 #elif defined(__aarch64__)
1733 __asm__
__volatile__( "mrs %0, fpsr" : "=r" (fpsr
) );
1734 if (fpsr
& 0x1) flags
|= _SW_INVALID
;
1735 if (fpsr
& 0x2) flags
|= _SW_ZERODIVIDE
;
1736 if (fpsr
& 0x4) flags
|= _SW_OVERFLOW
;
1737 if (fpsr
& 0x8) flags
|= _SW_UNDERFLOW
;
1738 if (fpsr
& 0x10) flags
|= _SW_INEXACT
;
1739 if (fpsr
& 0x80) flags
|= _SW_DENORMAL
;
1741 __asm__
__volatile__( "msr fpsr, %0" :: "r" (fpsr
) );
1743 FIXME( "not implemented\n" );
1748 /*********************************************************************
1749 * __fpecode (MSVCRT.@)
1751 int * CDECL
__fpecode(void)
1753 return &msvcrt_get_thread_data()->fpecode
;
1756 /*********************************************************************
1759 double CDECL
MSVCRT_ldexp(double num
, __msvcrt_long exp
)
1761 double z
= unix_funcs
->ldexp(num
,exp
);
1763 if (isfinite(num
) && !isfinite(z
))
1764 return math_error(_OVERFLOW
, "ldexp", num
, exp
, z
);
1765 if (num
&& isfinite(num
) && !z
)
1766 return math_error(_UNDERFLOW
, "ldexp", num
, exp
, z
);
1767 if (z
== 0 && signbit(z
))
1768 z
= 0.0; /* Convert -0 -> +0 */
1772 /*********************************************************************
1775 double CDECL
MSVCRT__cabs(struct _complex num
)
1777 return MSVCRT_sqrt(num
.x
* num
.x
+ num
.y
* num
.y
);
1780 /*********************************************************************
1781 * _chgsign (MSVCRT.@)
1783 double CDECL
MSVCRT__chgsign(double num
)
1785 union { double f
; UINT64 i
; } u
= { num
};
1790 /*********************************************************************
1791 * __control87_2 (MSVCR80.@)
1793 * Not exported by native msvcrt, added in msvcr80.
1796 int CDECL
__control87_2( unsigned int newval
, unsigned int mask
,
1797 unsigned int *x86_cw
, unsigned int *sse2_cw
)
1800 unsigned long fpword
;
1802 unsigned int old_flags
;
1806 __asm__
__volatile__( "fstcw %0" : "=m" (fpword
) );
1808 /* Convert into mask constants */
1810 if (fpword
& 0x1) flags
|= MSVCRT__EM_INVALID
;
1811 if (fpword
& 0x2) flags
|= MSVCRT__EM_DENORMAL
;
1812 if (fpword
& 0x4) flags
|= MSVCRT__EM_ZERODIVIDE
;
1813 if (fpword
& 0x8) flags
|= MSVCRT__EM_OVERFLOW
;
1814 if (fpword
& 0x10) flags
|= MSVCRT__EM_UNDERFLOW
;
1815 if (fpword
& 0x20) flags
|= MSVCRT__EM_INEXACT
;
1816 switch (fpword
& 0xc00)
1818 case 0xc00: flags
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
1819 case 0x800: flags
|= MSVCRT__RC_UP
; break;
1820 case 0x400: flags
|= MSVCRT__RC_DOWN
; break;
1822 switch (fpword
& 0x300)
1824 case 0x0: flags
|= MSVCRT__PC_24
; break;
1825 case 0x200: flags
|= MSVCRT__PC_53
; break;
1826 case 0x300: flags
|= MSVCRT__PC_64
; break;
1828 if (fpword
& 0x1000) flags
|= MSVCRT__IC_AFFINE
;
1830 TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags
, newval
, mask
);
1833 flags
= (flags
& ~mask
) | (newval
& mask
);
1835 /* Convert (masked) value back to fp word */
1837 if (flags
& MSVCRT__EM_INVALID
) fpword
|= 0x1;
1838 if (flags
& MSVCRT__EM_DENORMAL
) fpword
|= 0x2;
1839 if (flags
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x4;
1840 if (flags
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x8;
1841 if (flags
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x10;
1842 if (flags
& MSVCRT__EM_INEXACT
) fpword
|= 0x20;
1843 switch (flags
& MSVCRT__MCW_RC
)
1845 case MSVCRT__RC_UP
|MSVCRT__RC_DOWN
: fpword
|= 0xc00; break;
1846 case MSVCRT__RC_UP
: fpword
|= 0x800; break;
1847 case MSVCRT__RC_DOWN
: fpword
|= 0x400; break;
1849 switch (flags
& MSVCRT__MCW_PC
)
1851 case MSVCRT__PC_64
: fpword
|= 0x300; break;
1852 case MSVCRT__PC_53
: fpword
|= 0x200; break;
1853 case MSVCRT__PC_24
: fpword
|= 0x0; break;
1855 if (flags
& MSVCRT__IC_AFFINE
) fpword
|= 0x1000;
1857 __asm__
__volatile__( "fldcw %0" : : "m" (fpword
) );
1862 if (!sse2_cw
) return 1;
1866 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1868 /* Convert into mask constants */
1870 if (fpword
& 0x80) flags
|= MSVCRT__EM_INVALID
;
1871 if (fpword
& 0x100) flags
|= MSVCRT__EM_DENORMAL
;
1872 if (fpword
& 0x200) flags
|= MSVCRT__EM_ZERODIVIDE
;
1873 if (fpword
& 0x400) flags
|= MSVCRT__EM_OVERFLOW
;
1874 if (fpword
& 0x800) flags
|= MSVCRT__EM_UNDERFLOW
;
1875 if (fpword
& 0x1000) flags
|= MSVCRT__EM_INEXACT
;
1876 switch (fpword
& 0x6000)
1878 case 0x6000: flags
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
1879 case 0x4000: flags
|= MSVCRT__RC_UP
; break;
1880 case 0x2000: flags
|= MSVCRT__RC_DOWN
; break;
1882 switch (fpword
& 0x8040)
1884 case 0x0040: flags
|= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
; break;
1885 case 0x8000: flags
|= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
; break;
1886 case 0x8040: flags
|= MSVCRT__DN_FLUSH
; break;
1889 TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags
, newval
, mask
);
1893 mask
&= MSVCRT__MCW_EM
| MSVCRT__MCW_RC
| MSVCRT__MCW_DN
;
1894 flags
= (flags
& ~mask
) | (newval
& mask
);
1896 if (flags
!= old_flags
)
1898 /* Convert (masked) value back to fp word */
1900 if (flags
& MSVCRT__EM_INVALID
) fpword
|= 0x80;
1901 if (flags
& MSVCRT__EM_DENORMAL
) fpword
|= 0x100;
1902 if (flags
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x200;
1903 if (flags
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x400;
1904 if (flags
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x800;
1905 if (flags
& MSVCRT__EM_INEXACT
) fpword
|= 0x1000;
1906 switch (flags
& MSVCRT__MCW_RC
)
1908 case MSVCRT__RC_UP
|MSVCRT__RC_DOWN
: fpword
|= 0x6000; break;
1909 case MSVCRT__RC_UP
: fpword
|= 0x4000; break;
1910 case MSVCRT__RC_DOWN
: fpword
|= 0x2000; break;
1912 switch (flags
& MSVCRT__MCW_DN
)
1914 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
: fpword
|= 0x0040; break;
1915 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
: fpword
|= 0x8000; break;
1916 case MSVCRT__DN_FLUSH
: fpword
|= 0x8040; break;
1918 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
1927 FIXME( "not implemented\n" );
1933 /*********************************************************************
1934 * _control87 (MSVCRT.@)
1936 unsigned int CDECL
_control87(unsigned int newval
, unsigned int mask
)
1938 unsigned int flags
= 0;
1940 unsigned int sse2_cw
;
1942 __control87_2( newval
, mask
, &flags
, &sse2_cw
);
1944 if ((flags
^ sse2_cw
) & (MSVCRT__MCW_EM
| MSVCRT__MCW_RC
)) flags
|= MSVCRT__EM_AMBIGUOUS
;
1946 #elif defined(__x86_64__)
1947 unsigned long fpword
;
1948 unsigned int old_flags
;
1950 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1951 if (fpword
& 0x80) flags
|= MSVCRT__EM_INVALID
;
1952 if (fpword
& 0x100) flags
|= MSVCRT__EM_DENORMAL
;
1953 if (fpword
& 0x200) flags
|= MSVCRT__EM_ZERODIVIDE
;
1954 if (fpword
& 0x400) flags
|= MSVCRT__EM_OVERFLOW
;
1955 if (fpword
& 0x800) flags
|= MSVCRT__EM_UNDERFLOW
;
1956 if (fpword
& 0x1000) flags
|= MSVCRT__EM_INEXACT
;
1957 switch (fpword
& 0x6000)
1959 case 0x6000: flags
|= MSVCRT__RC_CHOP
; break;
1960 case 0x4000: flags
|= MSVCRT__RC_UP
; break;
1961 case 0x2000: flags
|= MSVCRT__RC_DOWN
; break;
1963 switch (fpword
& 0x8040)
1965 case 0x0040: flags
|= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
; break;
1966 case 0x8000: flags
|= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
; break;
1967 case 0x8040: flags
|= MSVCRT__DN_FLUSH
; break;
1970 mask
&= MSVCRT__MCW_EM
| MSVCRT__MCW_RC
| MSVCRT__MCW_DN
;
1971 flags
= (flags
& ~mask
) | (newval
& mask
);
1972 if (flags
!= old_flags
)
1975 if (flags
& MSVCRT__EM_INVALID
) fpword
|= 0x80;
1976 if (flags
& MSVCRT__EM_DENORMAL
) fpword
|= 0x100;
1977 if (flags
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x200;
1978 if (flags
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x400;
1979 if (flags
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x800;
1980 if (flags
& MSVCRT__EM_INEXACT
) fpword
|= 0x1000;
1981 switch (flags
& MSVCRT__MCW_RC
)
1983 case MSVCRT__RC_CHOP
: fpword
|= 0x6000; break;
1984 case MSVCRT__RC_UP
: fpword
|= 0x4000; break;
1985 case MSVCRT__RC_DOWN
: fpword
|= 0x2000; break;
1987 switch (flags
& MSVCRT__MCW_DN
)
1989 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
: fpword
|= 0x0040; break;
1990 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
: fpword
|= 0x8000; break;
1991 case MSVCRT__DN_FLUSH
: fpword
|= 0x8040; break;
1993 __asm__
__volatile__( "ldmxcsr %0" :: "m" (fpword
) );
1995 #elif defined(__aarch64__)
1998 __asm__
__volatile__( "mrs %0, fpcr" : "=r" (fpcr
) );
1999 if (!(fpcr
& 0x100)) flags
|= MSVCRT__EM_INVALID
;
2000 if (!(fpcr
& 0x200)) flags
|= MSVCRT__EM_ZERODIVIDE
;
2001 if (!(fpcr
& 0x400)) flags
|= MSVCRT__EM_OVERFLOW
;
2002 if (!(fpcr
& 0x800)) flags
|= MSVCRT__EM_UNDERFLOW
;
2003 if (!(fpcr
& 0x1000)) flags
|= MSVCRT__EM_INEXACT
;
2004 if (!(fpcr
& 0x8000)) flags
|= MSVCRT__EM_DENORMAL
;
2005 switch (fpcr
& 0xc00000)
2007 case 0x400000: flags
|= MSVCRT__RC_UP
; break;
2008 case 0x800000: flags
|= MSVCRT__RC_DOWN
; break;
2009 case 0xc00000: flags
|= MSVCRT__RC_CHOP
; break;
2011 flags
= (flags
& ~mask
) | (newval
& mask
);
2012 fpcr
&= ~0xc09f00ul
;
2013 if (!(flags
& MSVCRT__EM_INVALID
)) fpcr
|= 0x100;
2014 if (!(flags
& MSVCRT__EM_ZERODIVIDE
)) fpcr
|= 0x200;
2015 if (!(flags
& MSVCRT__EM_OVERFLOW
)) fpcr
|= 0x400;
2016 if (!(flags
& MSVCRT__EM_UNDERFLOW
)) fpcr
|= 0x800;
2017 if (!(flags
& MSVCRT__EM_INEXACT
)) fpcr
|= 0x1000;
2018 if (!(flags
& MSVCRT__EM_DENORMAL
)) fpcr
|= 0x8000;
2019 switch (flags
& MSVCRT__MCW_RC
)
2021 case MSVCRT__RC_CHOP
: fpcr
|= 0xc00000; break;
2022 case MSVCRT__RC_UP
: fpcr
|= 0x400000; break;
2023 case MSVCRT__RC_DOWN
: fpcr
|= 0x800000; break;
2025 __asm__
__volatile__( "msr fpcr, %0" :: "r" (fpcr
) );
2027 FIXME( "not implemented\n" );
2032 /*********************************************************************
2033 * _controlfp (MSVCRT.@)
2035 unsigned int CDECL
_controlfp(unsigned int newval
, unsigned int mask
)
2037 return _control87( newval
, mask
& ~MSVCRT__EM_DENORMAL
);
2040 /*********************************************************************
2041 * _set_controlfp (MSVCRT.@)
2043 void CDECL
_set_controlfp( unsigned int newval
, unsigned int mask
)
2045 _controlfp( newval
, mask
);
2048 /*********************************************************************
2049 * _controlfp_s (MSVCRT.@)
2051 int CDECL
_controlfp_s(unsigned int *cur
, unsigned int newval
, unsigned int mask
)
2053 static const unsigned int all_flags
= (MSVCRT__MCW_EM
| MSVCRT__MCW_IC
| MSVCRT__MCW_RC
|
2054 MSVCRT__MCW_PC
| MSVCRT__MCW_DN
);
2057 if (!MSVCRT_CHECK_PMT( !(newval
& mask
& ~all_flags
) ))
2059 if (cur
) *cur
= _controlfp( 0, 0 ); /* retrieve it anyway */
2062 val
= _controlfp( newval
, mask
);
2063 if (cur
) *cur
= val
;
2068 /*********************************************************************
2069 * fegetenv (MSVCR120.@)
2071 int CDECL
MSVCRT_fegetenv(fenv_t
*env
)
2073 env
->_Fe_ctl
= _controlfp(0, 0) & (MSVCRT__EM_INEXACT
| MSVCRT__EM_UNDERFLOW
|
2074 MSVCRT__EM_OVERFLOW
| MSVCRT__EM_ZERODIVIDE
| MSVCRT__EM_INVALID
| MSVCRT__RC_CHOP
);
2075 env
->_Fe_stat
= _statusfp();
2081 /*********************************************************************
2082 * __fpe_flt_rounds (UCRTBASE.@)
2084 int CDECL
__fpe_flt_rounds(void)
2086 unsigned int fpc
= _controlfp(0, 0) & MSVCRT__RC_CHOP
;
2091 case MSVCRT__RC_CHOP
: return 0;
2092 case MSVCRT__RC_NEAR
: return 1;
2093 case MSVCRT__RC_UP
: return 2;
2101 /*********************************************************************
2102 * fegetround (MSVCR120.@)
2104 int CDECL
MSVCRT_fegetround(void)
2106 return _controlfp(0, 0) & MSVCRT__RC_CHOP
;
2109 /*********************************************************************
2110 * fesetround (MSVCR120.@)
2112 int CDECL
MSVCRT_fesetround(int round_mode
)
2114 if (round_mode
& (~MSVCRT__RC_CHOP
))
2116 _controlfp(round_mode
, MSVCRT__RC_CHOP
);
2120 #endif /* _MSVCR_VER>=120 */
2122 /*********************************************************************
2123 * _copysign (MSVCRT.@)
2125 * Copied from musl: src/math/copysign.c
2127 double CDECL
MSVCRT__copysign( double x
, double y
)
2129 union { double f
; UINT64 i
; } ux
= { x
}, uy
= { y
};
2131 ux
.i
|= uy
.i
& 1ull << 63;
2135 /*********************************************************************
2136 * _finite (MSVCRT.@)
2138 int CDECL
MSVCRT__finite(double num
)
2140 union { double f
; UINT64 i
; } u
= { num
};
2141 return (u
.i
& ~0ull >> 1) < 0x7ffull
<< 52;
2144 /*********************************************************************
2145 * _fpreset (MSVCRT.@)
2147 void CDECL
_fpreset(void)
2149 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2150 const unsigned int x86_cw
= 0x27f;
2151 __asm__
__volatile__( "fninit; fldcw %0" : : "m" (x86_cw
) );
2154 const unsigned long sse2_cw
= 0x1f80;
2155 __asm__
__volatile__( "ldmxcsr %0" : : "m" (sse2_cw
) );
2158 FIXME( "not implemented\n" );
2163 /*********************************************************************
2164 * fesetenv (MSVCR120.@)
2166 int CDECL
MSVCRT_fesetenv(const fenv_t
*env
)
2168 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
2176 DWORD instruction_pointer
;
2184 TRACE( "(%p)\n", env
);
2186 if (!env
->_Fe_ctl
&& !env
->_Fe_stat
) {
2191 __asm__
__volatile__( "fnstenv %0" : "=m" (fenv
) );
2193 fenv
.control_word
&= ~0xc3d;
2194 if (env
->_Fe_ctl
& MSVCRT__EM_INVALID
) fenv
.control_word
|= 0x1;
2195 if (env
->_Fe_ctl
& MSVCRT__EM_ZERODIVIDE
) fenv
.control_word
|= 0x4;
2196 if (env
->_Fe_ctl
& MSVCRT__EM_OVERFLOW
) fenv
.control_word
|= 0x8;
2197 if (env
->_Fe_ctl
& MSVCRT__EM_UNDERFLOW
) fenv
.control_word
|= 0x10;
2198 if (env
->_Fe_ctl
& MSVCRT__EM_INEXACT
) fenv
.control_word
|= 0x20;
2199 switch (env
->_Fe_ctl
& MSVCRT__MCW_RC
)
2201 case MSVCRT__RC_UP
|MSVCRT__RC_DOWN
: fenv
.control_word
|= 0xc00; break;
2202 case MSVCRT__RC_UP
: fenv
.control_word
|= 0x800; break;
2203 case MSVCRT__RC_DOWN
: fenv
.control_word
|= 0x400; break;
2206 fenv
.status_word
&= ~0x3d;
2207 if (env
->_Fe_stat
& FE_INVALID
) fenv
.status_word
|= 0x1;
2208 if (env
->_Fe_stat
& FE_DIVBYZERO
) fenv
.status_word
|= 0x4;
2209 if (env
->_Fe_stat
& FE_OVERFLOW
) fenv
.status_word
|= 0x8;
2210 if (env
->_Fe_stat
& FE_UNDERFLOW
) fenv
.status_word
|= 0x10;
2211 if (env
->_Fe_stat
& FE_INEXACT
) fenv
.status_word
|= 0x20;
2213 __asm__
__volatile__( "fldenv %0" : : "m" (fenv
) : "st", "st(1)",
2214 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
2219 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
2221 if (env
->_Fe_ctl
& MSVCRT__EM_INVALID
) fpword
|= 0x80;
2222 if (env
->_Fe_ctl
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x200;
2223 if (env
->_Fe_ctl
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x400;
2224 if (env
->_Fe_ctl
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x800;
2225 if (env
->_Fe_ctl
& MSVCRT__EM_INEXACT
) fpword
|= 0x1000;
2226 switch (env
->_Fe_ctl
& MSVCRT__MCW_RC
)
2228 case MSVCRT__RC_CHOP
: fpword
|= 0x6000; break;
2229 case MSVCRT__RC_UP
: fpword
|= 0x4000; break;
2230 case MSVCRT__RC_DOWN
: fpword
|= 0x2000; break;
2232 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
2237 FIXME( "not implemented\n" );
2243 /*********************************************************************
2246 int CDECL
MSVCRT__isnan(double num
)
2248 union { double f
; UINT64 i
; } u
= { num
};
2249 return (u
.i
& ~0ull >> 1) > 0x7ffull
<< 52;
2252 /*********************************************************************
2255 double CDECL
MSVCRT__j0(double num
)
2257 /* FIXME: errno handling */
2258 return unix_funcs
->j0( num
);
2261 /*********************************************************************
2264 double CDECL
MSVCRT__j1(double num
)
2266 /* FIXME: errno handling */
2267 return unix_funcs
->j1( num
);
2270 /*********************************************************************
2273 double CDECL
MSVCRT__jn(int n
, double num
)
2275 /* FIXME: errno handling */
2276 return unix_funcs
->jn( n
, num
);
2279 /*********************************************************************
2282 double CDECL
MSVCRT__y0(double num
)
2286 if (!isfinite(num
)) *_errno() = EDOM
;
2287 retval
= unix_funcs
->y0( num
);
2288 if (MSVCRT__fpclass(retval
) == _FPCLASS_NINF
)
2296 /*********************************************************************
2299 double CDECL
MSVCRT__y1(double num
)
2303 if (!isfinite(num
)) *_errno() = EDOM
;
2304 retval
= unix_funcs
->y1( num
);
2305 if (MSVCRT__fpclass(retval
) == _FPCLASS_NINF
)
2313 /*********************************************************************
2316 double CDECL
MSVCRT__yn(int order
, double num
)
2320 if (!isfinite(num
)) *_errno() = EDOM
;
2321 retval
= unix_funcs
->yn( order
, num
);
2322 if (MSVCRT__fpclass(retval
) == _FPCLASS_NINF
)
2332 /*********************************************************************
2333 * _nearbyint (MSVCR120.@)
2335 double CDECL
MSVCRT_nearbyint(double num
)
2337 return unix_funcs
->nearbyint( num
);
2340 /*********************************************************************
2341 * _nearbyintf (MSVCR120.@)
2343 float CDECL
MSVCRT_nearbyintf(float num
)
2345 return unix_funcs
->nearbyintf( num
);
2348 /*********************************************************************
2349 * nexttoward (MSVCR120.@)
2351 double CDECL
MSVCRT_nexttoward(double num
, double next
)
2353 double ret
= unix_funcs
->nexttoward(num
, next
);
2354 if (!(MSVCRT__fpclass(ret
) & (_FPCLASS_PN
| _FPCLASS_NN
2355 | _FPCLASS_SNAN
| _FPCLASS_QNAN
)) && !isinf(num
))
2362 /*********************************************************************
2363 * nexttowardf (MSVCR120.@)
2365 float CDECL
MSVCRT_nexttowardf(float num
, double next
)
2367 float ret
= unix_funcs
->nexttowardf( num
, next
);
2368 if (!(MSVCRT__fpclass(ret
) & (_FPCLASS_PN
| _FPCLASS_NN
2369 | _FPCLASS_SNAN
| _FPCLASS_QNAN
)) && !isinf(num
))
2376 #endif /* _MSVCR_VER>=120 */
2378 /*********************************************************************
2379 * _nextafter (MSVCRT.@)
2381 double CDECL
MSVCRT__nextafter(double num
, double next
)
2384 if (!isfinite(num
) || !isfinite(next
)) *_errno() = EDOM
;
2385 retval
= unix_funcs
->nextafter(num
,next
);
2389 /*********************************************************************
2392 char * CDECL
MSVCRT__ecvt( double number
, int ndigits
, int *decpt
, int *sign
)
2395 thread_data_t
*data
= msvcrt_get_thread_data();
2396 /* FIXME: check better for overflow (native supports over 300 chars) */
2397 ndigits
= min( ndigits
, 80 - 7); /* 7 : space for dec point, 1 for "e",
2398 * 4 for exponent and one for
2399 * terminating '\0' */
2400 if (!data
->efcvt_buffer
)
2401 data
->efcvt_buffer
= malloc( 80 ); /* ought to be enough */
2408 /* handle cases with zero ndigits or less */
2410 if( prec
< 1) prec
= 2;
2411 len
= MSVCRT__snprintf(data
->efcvt_buffer
, 80, "%.*le", prec
- 1, number
);
2412 /* take the decimal "point away */
2414 memmove( data
->efcvt_buffer
+ 1, data
->efcvt_buffer
+ 2, len
- 1 );
2415 /* take the exponential "e" out */
2416 data
->efcvt_buffer
[ prec
] = '\0';
2417 /* read the exponent */
2418 MSVCRT_sscanf( data
->efcvt_buffer
+ prec
+ 1, "%d", decpt
);
2420 /* adjust for some border cases */
2421 if( data
->efcvt_buffer
[0] == '0')/* value is zero */
2423 /* handle cases with zero ndigits or less */
2425 if( data
->efcvt_buffer
[ 0] >= '5')
2427 data
->efcvt_buffer
[ 0] = '\0';
2429 TRACE("out=\"%s\"\n",data
->efcvt_buffer
);
2430 return data
->efcvt_buffer
;
2433 /*********************************************************************
2434 * _ecvt_s (MSVCRT.@)
2436 int CDECL
MSVCRT__ecvt_s( char *buffer
, size_t length
, double number
, int ndigits
, int *decpt
, int *sign
)
2440 const char infret
[] = "1#INF";
2442 if (!MSVCRT_CHECK_PMT(buffer
!= NULL
)) return EINVAL
;
2443 if (!MSVCRT_CHECK_PMT(decpt
!= NULL
)) return EINVAL
;
2444 if (!MSVCRT_CHECK_PMT(sign
!= NULL
)) return EINVAL
;
2445 if (!MSVCRT_CHECK_PMT_ERR( length
> 2, ERANGE
)) return ERANGE
;
2446 if (!MSVCRT_CHECK_PMT_ERR(ndigits
< (int)length
- 1, ERANGE
)) return ERANGE
;
2448 /* special case - inf */
2449 if(number
== HUGE_VAL
|| number
== -HUGE_VAL
)
2451 memset(buffer
, '0', ndigits
);
2452 memcpy(buffer
, infret
, min(ndigits
, sizeof(infret
) - 1 ) );
2453 buffer
[ndigits
] = '\0';
2455 if(number
== -HUGE_VAL
)
2461 /* handle cases with zero ndigits or less */
2463 if( prec
< 1) prec
= 2;
2464 result
= malloc(prec
+ 7);
2471 len
= MSVCRT__snprintf(result
, prec
+ 7, "%.*le", prec
- 1, number
);
2472 /* take the decimal "point away */
2474 memmove( result
+ 1, result
+ 2, len
- 1 );
2475 /* take the exponential "e" out */
2476 result
[ prec
] = '\0';
2477 /* read the exponent */
2478 MSVCRT_sscanf( result
+ prec
+ 1, "%d", decpt
);
2480 /* adjust for some border cases */
2481 if( result
[0] == '0')/* value is zero */
2483 /* handle cases with zero ndigits or less */
2485 if( result
[ 0] >= '5')
2489 memcpy( buffer
, result
, max(ndigits
+ 1, 1) );
2494 /***********************************************************************
2497 char * CDECL
MSVCRT__fcvt( double number
, int ndigits
, int *decpt
, int *sign
)
2499 thread_data_t
*data
= msvcrt_get_thread_data();
2500 int stop
, dec1
, dec2
;
2501 char *ptr1
, *ptr2
, *first
;
2502 char buf
[80]; /* ought to be enough */
2503 char decimal_separator
= get_locinfo()->lconv
->decimal_point
[0];
2505 if (!data
->efcvt_buffer
)
2506 data
->efcvt_buffer
= malloc( 80 ); /* ought to be enough */
2514 stop
= MSVCRT__snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
2516 ptr2
= data
->efcvt_buffer
;
2521 /* For numbers below the requested resolution, work out where
2522 the decimal point will be rather than finding it in the string */
2523 if (number
< 1.0 && number
> 0.0) {
2524 dec2
= MSVCRT_log10(number
+ 1e-10);
2525 if (-dec2
<= ndigits
) dec2
= 0;
2528 /* If requested digits is zero or less, we will need to truncate
2529 * the returned string */
2534 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
2535 while (*ptr1
!= '\0' && *ptr1
!= decimal_separator
) {
2536 if (!first
) first
= ptr2
;
2537 if ((ptr1
- buf
) < stop
) {
2548 while (*ptr1
== '0') { /* Process leading zeroes */
2553 while (*ptr1
!= '\0') {
2554 if (!first
) first
= ptr2
;
2561 /* We never found a non-zero digit, then our number is either
2562 * smaller than the requested precision, or 0.0 */
2567 first
= data
->efcvt_buffer
;
2572 *decpt
= dec2
? dec2
: dec1
;
2576 /***********************************************************************
2577 * _fcvt_s (MSVCRT.@)
2579 int CDECL
MSVCRT__fcvt_s(char* outbuffer
, size_t size
, double number
, int ndigits
, int *decpt
, int *sign
)
2581 int stop
, dec1
, dec2
;
2582 char *ptr1
, *ptr2
, *first
;
2583 char buf
[80]; /* ought to be enough */
2584 char decimal_separator
= get_locinfo()->lconv
->decimal_point
[0];
2586 if (!outbuffer
|| !decpt
|| !sign
|| size
== 0)
2598 stop
= MSVCRT__snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
2605 /* For numbers below the requested resolution, work out where
2606 the decimal point will be rather than finding it in the string */
2607 if (number
< 1.0 && number
> 0.0) {
2608 dec2
= MSVCRT_log10(number
+ 1e-10);
2609 if (-dec2
<= ndigits
) dec2
= 0;
2612 /* If requested digits is zero or less, we will need to truncate
2613 * the returned string */
2618 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
2619 while (*ptr1
!= '\0' && *ptr1
!= decimal_separator
) {
2620 if (!first
) first
= ptr2
;
2621 if ((ptr1
- buf
) < stop
) {
2635 while (*ptr1
== '0') { /* Process leading zeroes */
2636 if (number
== 0.0 && size
> 1) {
2644 while (*ptr1
!= '\0') {
2645 if (!first
) first
= ptr2
;
2655 /* We never found a non-zero digit, then our number is either
2656 * smaller than the requested precision, or 0.0 */
2657 if (!first
&& (number
<= 0.0))
2660 *decpt
= dec2
? dec2
: dec1
;
2664 /***********************************************************************
2667 char * CDECL
MSVCRT__gcvt( double number
, int ndigit
, char *buff
)
2679 MSVCRT_sprintf(buff
, "%.*g", ndigit
, number
);
2683 /***********************************************************************
2684 * _gcvt_s (MSVCRT.@)
2686 int CDECL
MSVCRT__gcvt_s(char *buff
, size_t size
, double number
, int digits
)
2695 if( digits
<0 || digits
>=size
) {
2703 len
= MSVCRT__scprintf("%.*g", digits
, number
);
2710 MSVCRT_sprintf(buff
, "%.*g", digits
, number
);
2714 #include <stdlib.h> /* div_t, ldiv_t */
2716 /*********************************************************************
2719 * [i386] Windows binary compatible - returns the struct in eax/edx.
2722 unsigned __int64 CDECL
MSVCRT_div(int num
, int denom
)
2726 unsigned __int64 uint64
;
2729 ret
.div
.quot
= num
/ denom
;
2730 ret
.div
.rem
= num
% denom
;
2734 /*********************************************************************
2737 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2739 div_t CDECL
MSVCRT_div(int num
, int denom
)
2743 ret
.quot
= num
/ denom
;
2744 ret
.rem
= num
% denom
;
2747 #endif /* ifdef __i386__ */
2750 /*********************************************************************
2753 * [i386] Windows binary compatible - returns the struct in eax/edx.
2756 unsigned __int64 CDECL
MSVCRT_ldiv(__msvcrt_long num
, __msvcrt_long denom
)
2760 unsigned __int64 uint64
;
2763 ret
.ldiv
.quot
= num
/ denom
;
2764 ret
.ldiv
.rem
= num
% denom
;
2768 /*********************************************************************
2771 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2773 ldiv_t CDECL
MSVCRT_ldiv(__msvcrt_long num
, __msvcrt_long denom
)
2777 ret
.quot
= num
/ denom
;
2778 ret
.rem
= num
% denom
;
2781 #endif /* ifdef __i386__ */
2784 /*********************************************************************
2785 * lldiv (MSVCR100.@)
2787 lldiv_t CDECL
MSVCRT_lldiv(__int64 num
, __int64 denom
)
2791 ret
.quot
= num
/ denom
;
2792 ret
.rem
= num
% denom
;
2800 /*********************************************************************
2801 * _adjust_fdiv (MSVCRT.@)
2802 * Used by the MSVC compiler to work around the Pentium FDIV bug.
2804 int MSVCRT__adjust_fdiv
= 0;
2806 /***********************************************************************
2807 * _adj_fdiv_m16i (MSVCRT.@)
2810 * I _think_ this function is intended to work around the Pentium
2813 void __stdcall
_adj_fdiv_m16i( short arg
)
2815 TRACE("(): stub\n");
2818 /***********************************************************************
2819 * _adj_fdiv_m32 (MSVCRT.@)
2822 * I _think_ this function is intended to work around the Pentium
2825 void __stdcall
_adj_fdiv_m32( unsigned int arg
)
2827 TRACE("(): stub\n");
2830 /***********************************************************************
2831 * _adj_fdiv_m32i (MSVCRT.@)
2834 * I _think_ this function is intended to work around the Pentium
2837 void __stdcall
_adj_fdiv_m32i( int arg
)
2839 TRACE("(): stub\n");
2842 /***********************************************************************
2843 * _adj_fdiv_m64 (MSVCRT.@)
2846 * I _think_ this function is intended to work around the Pentium
2849 void __stdcall
_adj_fdiv_m64( unsigned __int64 arg
)
2851 TRACE("(): stub\n");
2854 /***********************************************************************
2855 * _adj_fdiv_r (MSVCRT.@)
2857 * This function is likely to have the wrong number of arguments.
2860 * I _think_ this function is intended to work around the Pentium
2863 void _adj_fdiv_r(void)
2865 TRACE("(): stub\n");
2868 /***********************************************************************
2869 * _adj_fdivr_m16i (MSVCRT.@)
2872 * I _think_ this function is intended to work around the Pentium
2875 void __stdcall
_adj_fdivr_m16i( short arg
)
2877 TRACE("(): stub\n");
2880 /***********************************************************************
2881 * _adj_fdivr_m32 (MSVCRT.@)
2884 * I _think_ this function is intended to work around the Pentium
2887 void __stdcall
_adj_fdivr_m32( unsigned int arg
)
2889 TRACE("(): stub\n");
2892 /***********************************************************************
2893 * _adj_fdivr_m32i (MSVCRT.@)
2896 * I _think_ this function is intended to work around the Pentium
2899 void __stdcall
_adj_fdivr_m32i( int arg
)
2901 TRACE("(): stub\n");
2904 /***********************************************************************
2905 * _adj_fdivr_m64 (MSVCRT.@)
2908 * I _think_ this function is intended to work around the Pentium
2911 void __stdcall
_adj_fdivr_m64( unsigned __int64 arg
)
2913 TRACE("(): stub\n");
2916 /***********************************************************************
2917 * _adj_fpatan (MSVCRT.@)
2919 * This function is likely to have the wrong number of arguments.
2922 * I _think_ this function is intended to work around the Pentium
2925 void _adj_fpatan(void)
2927 TRACE("(): stub\n");
2930 /***********************************************************************
2931 * _adj_fprem (MSVCRT.@)
2933 * This function is likely to have the wrong number of arguments.
2936 * I _think_ this function is intended to work around the Pentium
2939 void _adj_fprem(void)
2941 TRACE("(): stub\n");
2944 /***********************************************************************
2945 * _adj_fprem1 (MSVCRT.@)
2947 * This function is likely to have the wrong number of arguments.
2950 * I _think_ this function is intended to work around the Pentium
2953 void _adj_fprem1(void)
2955 TRACE("(): stub\n");
2958 /***********************************************************************
2959 * _adj_fptan (MSVCRT.@)
2961 * This function is likely to have the wrong number of arguments.
2964 * I _think_ this function is intended to work around the Pentium
2967 void _adj_fptan(void)
2969 TRACE("(): stub\n");
2972 /***********************************************************************
2973 * _safe_fdiv (MSVCRT.@)
2975 * This function is likely to have the wrong number of arguments.
2978 * I _think_ this function is intended to work around the Pentium
2981 void _safe_fdiv(void)
2983 TRACE("(): stub\n");
2986 /***********************************************************************
2987 * _safe_fdivr (MSVCRT.@)
2989 * This function is likely to have the wrong number of arguments.
2992 * I _think_ this function is intended to work around the Pentium
2995 void _safe_fdivr(void)
2997 TRACE("(): stub\n");
3000 /***********************************************************************
3001 * _safe_fprem (MSVCRT.@)
3003 * This function is likely to have the wrong number of arguments.
3006 * I _think_ this function is intended to work around the Pentium
3009 void _safe_fprem(void)
3011 TRACE("(): stub\n");
3014 /***********************************************************************
3015 * _safe_fprem1 (MSVCRT.@)
3018 * This function is likely to have the wrong number of arguments.
3021 * I _think_ this function is intended to work around the Pentium
3024 void _safe_fprem1(void)
3026 TRACE("(): stub\n");
3029 /***********************************************************************
3030 * __libm_sse2_acos (MSVCRT.@)
3032 void __cdecl
MSVCRT___libm_sse2_acos(void)
3035 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3036 d
= MSVCRT_acos( d
);
3037 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3040 /***********************************************************************
3041 * __libm_sse2_acosf (MSVCRT.@)
3043 void __cdecl
MSVCRT___libm_sse2_acosf(void)
3046 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3047 f
= MSVCRT_acosf( f
);
3048 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3051 /***********************************************************************
3052 * __libm_sse2_asin (MSVCRT.@)
3054 void __cdecl
MSVCRT___libm_sse2_asin(void)
3057 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3058 d
= MSVCRT_asin( d
);
3059 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3062 /***********************************************************************
3063 * __libm_sse2_asinf (MSVCRT.@)
3065 void __cdecl
MSVCRT___libm_sse2_asinf(void)
3068 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3069 f
= MSVCRT_asinf( f
);
3070 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3073 /***********************************************************************
3074 * __libm_sse2_atan (MSVCRT.@)
3076 void __cdecl
MSVCRT___libm_sse2_atan(void)
3079 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3080 d
= MSVCRT_atan( d
);
3081 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3084 /***********************************************************************
3085 * __libm_sse2_atan2 (MSVCRT.@)
3087 void __cdecl
MSVCRT___libm_sse2_atan2(void)
3090 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
3091 d1
= MSVCRT_atan2( d1
, d2
);
3092 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
3095 /***********************************************************************
3096 * __libm_sse2_atanf (MSVCRT.@)
3098 void __cdecl
MSVCRT___libm_sse2_atanf(void)
3101 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3102 f
= MSVCRT_atanf( f
);
3103 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3106 /***********************************************************************
3107 * __libm_sse2_cos (MSVCRT.@)
3109 void __cdecl
MSVCRT___libm_sse2_cos(void)
3112 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3113 d
= MSVCRT_cos( d
);
3114 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3117 /***********************************************************************
3118 * __libm_sse2_cosf (MSVCRT.@)
3120 void __cdecl
MSVCRT___libm_sse2_cosf(void)
3123 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3124 f
= MSVCRT_cosf( f
);
3125 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3128 /***********************************************************************
3129 * __libm_sse2_exp (MSVCRT.@)
3131 void __cdecl
MSVCRT___libm_sse2_exp(void)
3134 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3135 d
= MSVCRT_exp( d
);
3136 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3139 /***********************************************************************
3140 * __libm_sse2_expf (MSVCRT.@)
3142 void __cdecl
MSVCRT___libm_sse2_expf(void)
3145 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3146 f
= MSVCRT_expf( f
);
3147 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3150 /***********************************************************************
3151 * __libm_sse2_log (MSVCRT.@)
3153 void __cdecl
MSVCRT___libm_sse2_log(void)
3156 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3157 d
= MSVCRT_log( d
);
3158 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3161 /***********************************************************************
3162 * __libm_sse2_log10 (MSVCRT.@)
3164 void __cdecl
MSVCRT___libm_sse2_log10(void)
3167 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3168 d
= MSVCRT_log10( d
);
3169 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3172 /***********************************************************************
3173 * __libm_sse2_log10f (MSVCRT.@)
3175 void __cdecl
MSVCRT___libm_sse2_log10f(void)
3178 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3179 f
= MSVCRT_log10f( f
);
3180 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3183 /***********************************************************************
3184 * __libm_sse2_logf (MSVCRT.@)
3186 void __cdecl
MSVCRT___libm_sse2_logf(void)
3189 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3190 f
= MSVCRT_logf( f
);
3191 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3194 /***********************************************************************
3195 * __libm_sse2_pow (MSVCRT.@)
3197 void __cdecl
MSVCRT___libm_sse2_pow(void)
3200 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
3201 d1
= MSVCRT_pow( d1
, d2
);
3202 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
3205 /***********************************************************************
3206 * __libm_sse2_powf (MSVCRT.@)
3208 void __cdecl
MSVCRT___libm_sse2_powf(void)
3211 __asm__
__volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1
), "=g" (f2
) );
3212 f1
= MSVCRT_powf( f1
, f2
);
3213 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f1
) );
3216 /***********************************************************************
3217 * __libm_sse2_sin (MSVCRT.@)
3219 void __cdecl
MSVCRT___libm_sse2_sin(void)
3222 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3223 d
= MSVCRT_sin( d
);
3224 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3227 /***********************************************************************
3228 * __libm_sse2_sinf (MSVCRT.@)
3230 void __cdecl
MSVCRT___libm_sse2_sinf(void)
3233 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3234 f
= MSVCRT_sinf( f
);
3235 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3238 /***********************************************************************
3239 * __libm_sse2_tan (MSVCRT.@)
3241 void __cdecl
MSVCRT___libm_sse2_tan(void)
3244 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3245 d
= MSVCRT_tan( d
);
3246 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3249 /***********************************************************************
3250 * __libm_sse2_tanf (MSVCRT.@)
3252 void __cdecl
MSVCRT___libm_sse2_tanf(void)
3255 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
3256 f
= MSVCRT_tanf( f
);
3257 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
3260 /***********************************************************************
3261 * __libm_sse2_sqrt_precise (MSVCR110.@)
3263 void __cdecl
MSVCRT___libm_sse2_sqrt_precise(void)
3266 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
3267 d
= MSVCRT_sqrt( d
);
3268 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
3271 #endif /* __i386__ */
3273 /*********************************************************************
3276 double CDECL
MSVCR120_cbrt(double x
)
3278 return unix_funcs
->cbrt( x
);
3281 /*********************************************************************
3282 * cbrtf (MSVCR120.@)
3284 float CDECL
MSVCR120_cbrtf(float x
)
3286 return unix_funcs
->cbrtf( x
);
3289 /*********************************************************************
3290 * cbrtl (MSVCR120.@)
3292 LDOUBLE CDECL
MSVCR120_cbrtl(LDOUBLE x
)
3294 return MSVCR120_cbrt(x
);
3297 /*********************************************************************
3300 double CDECL
MSVCR120_exp2(double x
)
3302 double ret
= unix_funcs
->exp2( x
);
3303 if (isfinite(x
) && !isfinite(ret
)) *_errno() = ERANGE
;
3307 /*********************************************************************
3308 * exp2f (MSVCR120.@)
3310 float CDECL
MSVCR120_exp2f(float x
)
3312 float ret
= unix_funcs
->exp2f( x
);
3313 if (isfinite(x
) && !isfinite(ret
)) *_errno() = ERANGE
;
3317 /*********************************************************************
3318 * exp2l (MSVCR120.@)
3320 LDOUBLE CDECL
MSVCR120_exp2l(LDOUBLE x
)
3322 return MSVCR120_exp2(x
);
3325 /*********************************************************************
3326 * expm1 (MSVCR120.@)
3328 double CDECL
MSVCR120_expm1(double x
)
3330 double ret
= unix_funcs
->expm1( x
);
3331 if (isfinite(x
) && !isfinite(ret
)) *_errno() = ERANGE
;
3335 /*********************************************************************
3336 * expm1f (MSVCR120.@)
3338 float CDECL
MSVCR120_expm1f(float x
)
3340 float ret
= unix_funcs
->expm1f( x
);
3341 if (isfinite(x
) && !isfinite(ret
)) *_errno() = ERANGE
;
3345 /*********************************************************************
3346 * expm1l (MSVCR120.@)
3348 LDOUBLE CDECL
MSVCR120_expm1l(LDOUBLE x
)
3350 return MSVCR120_expm1(x
);
3353 /*********************************************************************
3354 * log1p (MSVCR120.@)
3356 double CDECL
MSVCR120_log1p(double x
)
3358 if (x
< -1) *_errno() = EDOM
;
3359 else if (x
== -1) *_errno() = ERANGE
;
3360 return unix_funcs
->log1p( x
);
3363 /*********************************************************************
3364 * log1pf (MSVCR120.@)
3366 float CDECL
MSVCR120_log1pf(float x
)
3368 if (x
< -1) *_errno() = EDOM
;
3369 else if (x
== -1) *_errno() = ERANGE
;
3370 return unix_funcs
->log1pf( x
);
3373 /*********************************************************************
3374 * log1pl (MSVCR120.@)
3376 LDOUBLE CDECL
MSVCR120_log1pl(LDOUBLE x
)
3378 return MSVCR120_log1p(x
);
3381 /*********************************************************************
3384 double CDECL
MSVCR120_log2(double x
)
3386 if (x
< 0) *_errno() = EDOM
;
3387 else if (x
== 0) *_errno() = ERANGE
;
3388 return unix_funcs
->log2( x
);
3391 /*********************************************************************
3392 * log2f (MSVCR120.@)
3394 float CDECL
MSVCR120_log2f(float x
)
3396 if (x
< 0) *_errno() = EDOM
;
3397 else if (x
== 0) *_errno() = ERANGE
;
3398 return unix_funcs
->log2f( x
);
3401 /*********************************************************************
3402 * log2l (MSVCR120.@)
3404 LDOUBLE CDECL
MSVCR120_log2l(LDOUBLE x
)
3406 return MSVCR120_log2(x
);
3409 /*********************************************************************
3412 double CDECL
MSVCR120_rint(double x
)
3414 return unix_funcs
->rint(x
);
3417 /*********************************************************************
3418 * rintf (MSVCR120.@)
3420 float CDECL
MSVCR120_rintf(float x
)
3422 return unix_funcs
->rintf(x
);
3425 /*********************************************************************
3426 * rintl (MSVCR120.@)
3428 LDOUBLE CDECL
MSVCR120_rintl(LDOUBLE x
)
3430 return MSVCR120_rint(x
);
3433 /*********************************************************************
3434 * lrint (MSVCR120.@)
3436 __msvcrt_long CDECL
MSVCR120_lrint(double x
)
3438 return unix_funcs
->lrint( x
);
3441 /*********************************************************************
3442 * lrintf (MSVCR120.@)
3444 __msvcrt_long CDECL
MSVCR120_lrintf(float x
)
3446 return unix_funcs
->lrintf( x
);
3449 /*********************************************************************
3450 * lrintl (MSVCR120.@)
3452 __msvcrt_long CDECL
MSVCR120_lrintl(LDOUBLE x
)
3454 return MSVCR120_lrint(x
);
3457 /*********************************************************************
3458 * llrint (MSVCR120.@)
3460 __int64 CDECL
MSVCR120_llrint(double x
)
3462 return unix_funcs
->llrint( x
);
3465 /*********************************************************************
3466 * llrintf (MSVCR120.@)
3468 __int64 CDECL
MSVCR120_llrintf(float x
)
3470 return unix_funcs
->llrintf( x
);
3473 /*********************************************************************
3474 * rintl (MSVCR120.@)
3476 __int64 CDECL
MSVCR120_llrintl(LDOUBLE x
)
3478 return MSVCR120_llrint(x
);
3483 /*********************************************************************
3484 * round (MSVCR120.@)
3486 double CDECL
MSVCR120_round(double x
)
3488 return unix_funcs
->round(x
);
3491 /*********************************************************************
3492 * roundf (MSVCR120.@)
3494 float CDECL
MSVCR120_roundf(float x
)
3496 return unix_funcs
->roundf(x
);
3499 /*********************************************************************
3500 * roundl (MSVCR120.@)
3502 LDOUBLE CDECL
MSVCR120_roundl(LDOUBLE x
)
3504 return MSVCR120_round(x
);
3507 /*********************************************************************
3508 * lround (MSVCR120.@)
3510 __msvcrt_long CDECL
MSVCR120_lround(double x
)
3512 return unix_funcs
->lround( x
);
3515 /*********************************************************************
3516 * lroundf (MSVCR120.@)
3518 __msvcrt_long CDECL
MSVCR120_lroundf(float x
)
3520 return unix_funcs
->lroundf( x
);
3523 /*********************************************************************
3524 * lroundl (MSVCR120.@)
3526 __msvcrt_long CDECL
MSVCR120_lroundl(LDOUBLE x
)
3528 return MSVCR120_lround(x
);
3531 /*********************************************************************
3532 * llround (MSVCR120.@)
3534 __int64 CDECL
MSVCR120_llround(double x
)
3536 return unix_funcs
->llround( x
);
3539 /*********************************************************************
3540 * llroundf (MSVCR120.@)
3542 __int64 CDECL
MSVCR120_llroundf(float x
)
3544 return unix_funcs
->llroundf( x
);
3547 /*********************************************************************
3548 * roundl (MSVCR120.@)
3550 __int64 CDECL
MSVCR120_llroundl(LDOUBLE x
)
3552 return MSVCR120_llround(x
);
3555 /*********************************************************************
3556 * trunc (MSVCR120.@)
3558 double CDECL
MSVCR120_trunc(double x
)
3560 return unix_funcs
->trunc(x
);
3563 /*********************************************************************
3564 * truncf (MSVCR120.@)
3566 float CDECL
MSVCR120_truncf(float x
)
3568 return unix_funcs
->truncf(x
);
3571 /*********************************************************************
3572 * truncl (MSVCR120.@)
3574 LDOUBLE CDECL
MSVCR120_truncl(LDOUBLE x
)
3576 return MSVCR120_trunc(x
);
3579 /*********************************************************************
3580 * _dclass (MSVCR120.@)
3582 * Copied from musl: src/math/__fpclassify.c
3584 short CDECL
MSVCR120__dclass(double x
)
3586 union { double f
; UINT64 i
; } u
= { x
};
3587 int e
= u
.i
>> 52 & 0x7ff;
3589 if (!e
) return u
.i
<< 1 ? MSVCRT_FP_SUBNORMAL
: MSVCRT_FP_ZERO
;
3590 if (e
== 0x7ff) return (u
.i
<< 12) ? MSVCRT_FP_NAN
: MSVCRT_FP_INFINITE
;
3591 return MSVCRT_FP_NORMAL
;
3594 /*********************************************************************
3595 * _fdclass (MSVCR120.@)
3597 * Copied from musl: src/math/__fpclassifyf.c
3599 short CDECL
MSVCR120__fdclass(float x
)
3601 union { float f
; UINT32 i
; } u
= { x
};
3602 int e
= u
.i
>> 23 & 0xff;
3604 if (!e
) return u
.i
<< 1 ? MSVCRT_FP_SUBNORMAL
: MSVCRT_FP_ZERO
;
3605 if (e
== 0xff) return u
.i
<< 9 ? MSVCRT_FP_NAN
: MSVCRT_FP_INFINITE
;
3606 return MSVCRT_FP_NORMAL
;
3609 /*********************************************************************
3610 * _ldclass (MSVCR120.@)
3612 short CDECL
MSVCR120__ldclass(LDOUBLE x
)
3614 return MSVCR120__dclass(x
);
3617 /*********************************************************************
3618 * _dtest (MSVCR120.@)
3620 short CDECL
MSVCR120__dtest(double *x
)
3622 return MSVCR120__dclass(*x
);
3625 /*********************************************************************
3626 * _fdtest (MSVCR120.@)
3628 short CDECL
MSVCR120__fdtest(float *x
)
3630 return MSVCR120__fdclass(*x
);
3633 /*********************************************************************
3634 * _ldtest (MSVCR120.@)
3636 short CDECL
MSVCR120__ldtest(LDOUBLE
*x
)
3638 return MSVCR120__dclass(*x
);
3641 /*********************************************************************
3644 double CDECL
MSVCR120_erf(double x
)
3646 return unix_funcs
->erf( x
);
3649 /*********************************************************************
3652 float CDECL
MSVCR120_erff(float x
)
3654 return unix_funcs
->erff( x
);
3657 /*********************************************************************
3660 LDOUBLE CDECL
MSVCR120_erfl(LDOUBLE x
)
3662 return MSVCR120_erf(x
);
3665 /*********************************************************************
3668 double CDECL
MSVCR120_erfc(double x
)
3670 return unix_funcs
->erfc( x
);
3673 /*********************************************************************
3674 * erfcf (MSVCR120.@)
3676 float CDECL
MSVCR120_erfcf(float x
)
3678 return unix_funcs
->erfcf( x
);
3681 /*********************************************************************
3682 * erfcl (MSVCR120.@)
3684 LDOUBLE CDECL
MSVCR120_erfcl(LDOUBLE x
)
3686 return MSVCR120_erfc(x
);
3689 /*********************************************************************
3690 * fmaxf (MSVCR120.@)
3692 float CDECL
MSVCR120_fmaxf(float x
, float y
)
3699 return signbit(x
) ? y
: x
;
3703 /*********************************************************************
3706 double CDECL
MSVCR120_fmax(double x
, double y
)
3713 return signbit(x
) ? y
: x
;
3717 /*********************************************************************
3718 * fdimf (MSVCR120.@)
3720 float CDECL
MSVCR120_fdimf(float x
, float y
)
3726 return x
>y
? x
-y
: 0;
3729 /*********************************************************************
3732 double CDECL
MSVCR120_fdim(double x
, double y
)
3738 return x
>y
? x
-y
: 0;
3741 /*********************************************************************
3742 * _fdsign (MSVCR120.@)
3744 int CDECL
MSVCR120__fdsign(float x
)
3746 union { float f
; UINT32 i
; } u
= { x
};
3747 return (u
.i
>> 16) & 0x8000;
3750 /*********************************************************************
3751 * _dsign (MSVCR120.@)
3753 int CDECL
MSVCR120__dsign(double x
)
3755 union { double f
; UINT64 i
; } u
= { x
};
3756 return (u
.i
>> 48) & 0x8000;
3760 /*********************************************************************
3761 * _dpcomp (MSVCR120.@)
3763 int CDECL
MSVCR120__dpcomp(double x
, double y
)
3765 if(isnan(x
) || isnan(y
))
3768 if(x
== y
) return 2;
3769 return x
< y
? 1 : 4;
3772 /*********************************************************************
3773 * _fdpcomp (MSVCR120.@)
3775 int CDECL
MSVCR120__fdpcomp(float x
, float y
)
3777 return MSVCR120__dpcomp(x
, y
);
3780 /*********************************************************************
3781 * fminf (MSVCR120.@)
3783 float CDECL
MSVCR120_fminf(float x
, float y
)
3790 return signbit(x
) ? x
: y
;
3794 /*********************************************************************
3797 double CDECL
MSVCR120_fmin(double x
, double y
)
3804 return signbit(x
) ? x
: y
;
3808 /*********************************************************************
3809 * asinh (MSVCR120.@)
3811 double CDECL
MSVCR120_asinh(double x
)
3813 return unix_funcs
->asinh( x
);
3816 /*********************************************************************
3817 * asinhf (MSVCR120.@)
3819 float CDECL
MSVCR120_asinhf(float x
)
3821 return unix_funcs
->asinhf( x
);
3824 /*********************************************************************
3825 * asinhl (MSVCR120.@)
3827 LDOUBLE CDECL
MSVCR120_asinhl(LDOUBLE x
)
3829 return MSVCR120_asinh(x
);
3832 /*********************************************************************
3833 * acosh (MSVCR120.@)
3835 double CDECL
MSVCR120_acosh(double x
)
3842 MSVCRT_fegetenv(&env
);
3843 env
._Fe_stat
|= FE_INVALID
;
3844 MSVCRT_fesetenv(&env
);
3847 return unix_funcs
->acosh( x
);
3850 /*********************************************************************
3851 * acoshf (MSVCR120.@)
3853 float CDECL
MSVCR120_acoshf(float x
)
3860 MSVCRT_fegetenv(&env
);
3861 env
._Fe_stat
|= FE_INVALID
;
3862 MSVCRT_fesetenv(&env
);
3865 return unix_funcs
->acoshf( x
);
3868 /*********************************************************************
3869 * acoshl (MSVCR120.@)
3871 LDOUBLE CDECL
MSVCR120_acoshl(LDOUBLE x
)
3873 return MSVCR120_acosh(x
);
3876 /*********************************************************************
3877 * atanh (MSVCR120.@)
3879 double CDECL
MSVCR120_atanh(double x
)
3883 if (x
> 1 || x
< -1) {
3888 /* on Linux atanh returns -NAN in this case */
3889 MSVCRT_fegetenv(&env
);
3890 env
._Fe_stat
|= FE_INVALID
;
3891 MSVCRT_fesetenv(&env
);
3894 ret
= unix_funcs
->atanh( x
);
3896 if (!isfinite(ret
)) *_errno() = ERANGE
;
3900 /*********************************************************************
3901 * atanhf (MSVCR120.@)
3903 float CDECL
MSVCR120_atanhf(float x
)
3907 if (x
> 1 || x
< -1) {
3912 MSVCRT_fegetenv(&env
);
3913 env
._Fe_stat
|= FE_INVALID
;
3914 MSVCRT_fesetenv(&env
);
3918 ret
= unix_funcs
->atanh( x
);
3920 if (!isfinite(ret
)) *_errno() = ERANGE
;
3924 /*********************************************************************
3925 * atanhl (MSVCR120.@)
3927 LDOUBLE CDECL
MSVCR120_atanhl(LDOUBLE x
)
3929 return MSVCR120_atanh(x
);
3932 #endif /* _MSVCR_VER>=120 */
3934 /*********************************************************************
3936 * scalbn (MSVCR120.@)
3937 * scalbln (MSVCR120.@)
3939 double CDECL
MSVCRT__scalb(double num
, __msvcrt_long power
)
3941 return MSVCRT_ldexp(num
, power
);
3944 /*********************************************************************
3945 * _scalbf (MSVCRT.@)
3946 * scalbnf (MSVCR120.@)
3947 * scalblnf (MSVCR120.@)
3949 float CDECL
MSVCRT__scalbf(float num
, __msvcrt_long power
)
3951 return MSVCRT_ldexp(num
, power
);
3956 /*********************************************************************
3957 * scalbnl (MSVCR120.@)
3958 * scalblnl (MSVCR120.@)
3960 LDOUBLE CDECL
MSVCR120_scalbnl(LDOUBLE num
, __msvcrt_long power
)
3962 return MSVCRT__scalb(num
, power
);
3965 /*********************************************************************
3966 * remainder (MSVCR120.@)
3968 double CDECL
MSVCR120_remainder(double x
, double y
)
3970 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3971 if(!isfinite(x
)) *_errno() = EDOM
;
3972 if(isnan(y
) || y
==0.0) *_errno() = EDOM
;
3973 return unix_funcs
->remainder( x
, y
);
3976 /*********************************************************************
3977 * remainderf (MSVCR120.@)
3979 float CDECL
MSVCR120_remainderf(float x
, float y
)
3981 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3982 if(!isfinite(x
)) *_errno() = EDOM
;
3983 if(isnan(y
) || y
==0.0f
) *_errno() = EDOM
;
3984 return unix_funcs
->remainderf( x
, y
);
3987 /*********************************************************************
3988 * remainderl (MSVCR120.@)
3990 LDOUBLE CDECL
MSVCR120_remainderl(LDOUBLE x
, LDOUBLE y
)
3992 return MSVCR120_remainder(x
, y
);
3995 /*********************************************************************
3996 * remquo (MSVCR120.@)
3998 double CDECL
MSVCR120_remquo(double x
, double y
, int *quo
)
4000 if(!isfinite(x
)) *_errno() = EDOM
;
4001 if(isnan(y
) || y
==0.0) *_errno() = EDOM
;
4002 return unix_funcs
->remquo( x
, y
, quo
);
4005 /*********************************************************************
4006 * remquof (MSVCR120.@)
4008 float CDECL
MSVCR120_remquof(float x
, float y
, int *quo
)
4010 if(!isfinite(x
)) *_errno() = EDOM
;
4011 if(isnan(y
) || y
==0.0f
) *_errno() = EDOM
;
4012 return unix_funcs
->remquof( x
, y
, quo
);
4015 /*********************************************************************
4016 * remquol (MSVCR120.@)
4018 LDOUBLE CDECL
MSVCR120_remquol(LDOUBLE x
, LDOUBLE y
, int *quo
)
4020 return MSVCR120_remquo(x
, y
, quo
);
4023 /*********************************************************************
4024 * lgamma (MSVCR120.@)
4026 double CDECL
MSVCR120_lgamma(double x
)
4028 return unix_funcs
->lgamma( x
);
4031 /*********************************************************************
4032 * lgammaf (MSVCR120.@)
4034 float CDECL
MSVCR120_lgammaf(float x
)
4036 return unix_funcs
->lgammaf( x
);
4039 /*********************************************************************
4040 * lgammal (MSVCR120.@)
4042 LDOUBLE CDECL
MSVCR120_lgammal(LDOUBLE x
)
4044 return MSVCR120_lgamma(x
);
4047 /*********************************************************************
4048 * tgamma (MSVCR120.@)
4050 double CDECL
MSVCR120_tgamma(double x
)
4052 return unix_funcs
->tgamma( x
);
4055 /*********************************************************************
4056 * tgammaf (MSVCR120.@)
4058 float CDECL
MSVCR120_tgammaf(float x
)
4060 return unix_funcs
->tgammaf( x
);
4063 /*********************************************************************
4066 double CDECL
MSVCR120_nan(const char *tagp
)
4068 /* Windows ignores input (MSDN) */
4072 /*********************************************************************
4075 float CDECL
MSVCR120_nanf(const char *tagp
)
4080 /*********************************************************************
4081 * _except1 (MSVCR120.@)
4083 * - find meaning of ignored cw and operation bits
4086 double CDECL
_except1(DWORD fpe
, _FP_OPERATION_CODE op
, double arg
, double res
, DWORD cw
, void *unk
)
4088 ULONG_PTR exception_arg
;
4089 DWORD exception
= 0;
4094 TRACE("(%x %x %lf %lf %x %p)\n", fpe
, op
, arg
, res
, cw
, unk
);
4097 cw
= ((cw
>> 7) & 0x3f) | ((cw
>> 3) & 0xc00);
4099 operation
= op
<< 5;
4100 exception_arg
= (ULONG_PTR
)&operation
;
4102 MSVCRT_fegetenv(&env
);
4104 if (fpe
& 0x1) { /* overflow */
4105 if ((fpe
== 0x1 && (cw
& 0x8)) || (fpe
==0x11 && (cw
& 0x28))) {
4106 /* 32-bit version also sets SW_INEXACT here */
4107 env
._Fe_stat
|= FE_OVERFLOW
;
4108 if (fpe
& 0x10) env
._Fe_stat
|= FE_INEXACT
;
4109 res
= signbit(res
) ? -INFINITY
: INFINITY
;
4111 exception
= EXCEPTION_FLT_OVERFLOW
;
4113 } else if (fpe
& 0x2) { /* underflow */
4114 if ((fpe
== 0x2 && (cw
& 0x10)) || (fpe
==0x12 && (cw
& 0x30))) {
4115 env
._Fe_stat
|= FE_UNDERFLOW
;
4116 if (fpe
& 0x10) env
._Fe_stat
|= FE_INEXACT
;
4117 res
= signbit(res
) ? -0.0 : 0.0;
4119 exception
= EXCEPTION_FLT_UNDERFLOW
;
4121 } else if (fpe
& 0x4) { /* zerodivide */
4122 if ((fpe
== 0x4 && (cw
& 0x4)) || (fpe
==0x14 && (cw
& 0x24))) {
4123 env
._Fe_stat
|= FE_DIVBYZERO
;
4124 if (fpe
& 0x10) env
._Fe_stat
|= FE_INEXACT
;
4126 exception
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
4128 } else if (fpe
& 0x8) { /* invalid */
4129 if (fpe
== 0x8 && (cw
& 0x1)) {
4130 env
._Fe_stat
|= FE_INVALID
;
4132 exception
= EXCEPTION_FLT_INVALID_OPERATION
;
4134 } else if (fpe
& 0x10) { /* inexact */
4135 if (fpe
== 0x10 && (cw
& 0x20)) {
4136 env
._Fe_stat
|= FE_INEXACT
;
4138 exception
= EXCEPTION_FLT_INEXACT_RESULT
;
4144 MSVCRT_fesetenv(&env
);
4146 RaiseException(exception
, 0, 1, &exception_arg
);
4148 if (cw
& 0x1) fpword
|= MSVCRT__EM_INVALID
;
4149 if (cw
& 0x2) fpword
|= MSVCRT__EM_DENORMAL
;
4150 if (cw
& 0x4) fpword
|= MSVCRT__EM_ZERODIVIDE
;
4151 if (cw
& 0x8) fpword
|= MSVCRT__EM_OVERFLOW
;
4152 if (cw
& 0x10) fpword
|= MSVCRT__EM_UNDERFLOW
;
4153 if (cw
& 0x20) fpword
|= MSVCRT__EM_INEXACT
;
4156 case 0xc00: fpword
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
4157 case 0x800: fpword
|= MSVCRT__RC_UP
; break;
4158 case 0x400: fpword
|= MSVCRT__RC_DOWN
; break;
4162 case 0x0: fpword
|= MSVCRT__PC_24
; break;
4163 case 0x200: fpword
|= MSVCRT__PC_53
; break;
4164 case 0x300: fpword
|= MSVCRT__PC_64
; break;
4166 if (cw
& 0x1000) fpword
|= MSVCRT__IC_AFFINE
;
4167 _control87(fpword
, 0xffffffff);
4172 _Dcomplex
* CDECL
MSVCR120__Cbuild(_Dcomplex
*ret
, double r
, double i
)
4179 double CDECL
MSVCR120_creal(_Dcomplex z
)
4184 /*********************************************************************
4185 * ilogb (MSVCR120.@)
4187 * Copied from musl: src/math/ilogb.c
4189 int CDECL
MSVCR120_ilogb(double x
)
4191 union { double f
; UINT64 i
; } u
= { x
};
4192 int e
= u
.i
>> 52 & 0x7ff;
4197 if (u
.i
== 0) return FP_ILOGB0
;
4199 for (e
= -0x3ff; u
.i
>> 63 == 0; e
--, u
.i
<<= 1);
4202 if (e
== 0x7ff) return u
.i
<< 12 ? FP_ILOGBNAN
: INT_MAX
;
4206 /*********************************************************************
4207 * ilogbf (MSVCR120.@)
4209 * Copied from musl: src/math/ilogbf.c
4211 int CDECL
MSVCR120_ilogbf(float x
)
4213 union { float f
; UINT32 i
; } u
= { x
};
4214 int e
= u
.i
>> 23 & 0xff;
4219 if (u
.i
== 0) return FP_ILOGB0
;
4221 for (e
= -0x7f; u
.i
>> 31 == 0; e
--, u
.i
<<= 1);
4224 if (e
== 0xff) return u
.i
<< 9 ? FP_ILOGBNAN
: INT_MAX
;
4228 /*********************************************************************
4229 * ilogbl (MSVCR120.@)
4231 int CDECL
MSVCR120_ilogbl(LDOUBLE x
)
4233 return MSVCR120_ilogb(x
);
4236 #endif /* _MSVCR_VER>=120 */