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
);
58 #define _DOMAIN 1 /* domain error in argument */
59 #define _SING 2 /* singularity */
60 #define _OVERFLOW 3 /* range overflow */
61 #define _UNDERFLOW 4 /* range underflow */
63 typedef int (CDECL
*MSVCRT_matherr_func
)(struct _exception
*);
65 static MSVCRT_matherr_func MSVCRT_default_matherr_func
= NULL
;
68 static BOOL sse2_enabled
;
70 void msvcrt_init_math( void *module
)
72 sse2_supported
= IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE
);
76 sse2_enabled
= sse2_supported
;
80 #if defined(__i386__) || defined(__x86_64__)
81 static inline double ret_nan( BOOL update_sw
)
84 if (!update_sw
) return -NAN
;
85 return (x
- x
) / (x
- x
);
89 #define SET_X87_CW(MASK) \
91 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
93 "movw (%esp), %ax\n\t" \
94 "movw %ax, 2(%esp)\n\t" \
95 "testw $" #MASK ", %ax\n\t" \
97 "andw $~" #MASK ", %ax\n\t" \
98 "movw %ax, 2(%esp)\n\t" \
102 #define RESET_X87_CW \
103 "movw (%esp), %ax\n\t" \
104 "cmpw %ax, 2(%esp)\n\t" \
106 "fstpl 8(%esp)\n\t" \
111 "addl $4, %esp\n\t" \
112 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
114 /*********************************************************************
115 * _matherr (CRTDLL.@)
117 int CDECL
_matherr(struct _exception
*e
)
123 double math_error(int type
, const char *name
, double arg1
, double arg2
, double retval
)
125 struct _exception exception
= {type
, (char *)name
, arg1
, arg2
, retval
};
127 TRACE("(%d, %s, %g, %g, %g)\n", type
, debugstr_a(name
), arg1
, arg2
, retval
);
129 if (MSVCRT_default_matherr_func
&& MSVCRT_default_matherr_func(&exception
))
130 return exception
.retval
;
135 /* don't set errno */
145 /* don't set errno */
148 ERR("Unhandled math error!\n");
151 return exception
.retval
;
154 /*********************************************************************
155 * __setusermatherr (MSVCRT.@)
157 void CDECL
__setusermatherr(MSVCRT_matherr_func func
)
159 MSVCRT_default_matherr_func
= func
;
160 TRACE("new matherr handler %p\n", func
);
163 /*********************************************************************
164 * _set_SSE2_enable (MSVCRT.@)
166 int CDECL
_set_SSE2_enable(int flag
)
168 sse2_enabled
= flag
&& sse2_supported
;
174 /*********************************************************************
175 * _get_FMA3_enable (UCRTBASE.@)
177 int CDECL
_get_FMA3_enable(void)
185 /*********************************************************************
186 * _set_FMA3_enable (MSVCR120.@)
188 int CDECL
_set_FMA3_enable(int flag
)
190 FIXME("(%x) stub\n", flag
);
196 #if !defined(__i386__) || _MSVCR_VER>=120
198 /*********************************************************************
199 * _chgsignf (MSVCRT.@)
201 float CDECL
_chgsignf( float num
)
203 union { float f
; UINT32 i
; } u
= { num
};
212 /*********************************************************************
213 * _fpclassf (MSVCRT.@)
215 int CDECL
_fpclassf( float num
)
217 union { float f
; UINT32 i
; } u
= { num
};
218 int e
= u
.i
>> 23 & 0xff;
224 if (u
.i
<< 1) return s
? _FPCLASS_ND
: _FPCLASS_PD
;
225 return s
? _FPCLASS_NZ
: _FPCLASS_PZ
;
227 if (u
.i
<< 9) return ((u
.i
>> 22) & 1) ? _FPCLASS_QNAN
: _FPCLASS_SNAN
;
228 return s
? _FPCLASS_NINF
: _FPCLASS_PINF
;
230 return s
? _FPCLASS_NN
: _FPCLASS_PN
;
234 /*********************************************************************
235 * _finitef (MSVCRT.@)
237 int CDECL
_finitef( float num
)
239 union { float f
; UINT32 i
; } u
= { num
};
240 return (u
.i
& 0x7fffffff) < 0x7f800000;
243 /*********************************************************************
246 int CDECL
_isnanf( float num
)
248 union { float f
; UINT32 i
; } u
= { num
};
249 return (u
.i
& 0x7fffffff) > 0x7f800000;
252 /*********************************************************************
255 #if _MSVCR_VER == 0 /* other versions call atanf() directly */
256 float CDECL
MSVCRT_atanf( float x
)
258 if (isnan(x
)) return math_error(_DOMAIN
, "atanf", x
, 0, x
);
264 extern short CDECL
_fdclass(float x
);
266 static BOOL
sqrtf_validate( float *x
)
268 short c
= _fdclass(*x
);
270 if (c
== FP_ZERO
) return FALSE
;
271 if (c
== FP_NAN
) return FALSE
;
274 *x
= math_error(_DOMAIN
, "sqrtf", *x
, 0, ret_nan(TRUE
));
277 if (c
== FP_INFINITE
) return FALSE
;
281 float CDECL
sse2_sqrtf(float);
282 __ASM_GLOBAL_FUNC( sse2_sqrtf
,
283 "sqrtss %xmm0, %xmm0\n\t"
287 /*********************************************************************
290 float CDECL
MSVCRT_sqrtf( float x
)
293 if (!sqrtf_validate(&x
))
296 return sse2_sqrtf(x
);
302 /*********************************************************************
305 #if _MSVCR_VER < 140 /* other versions call tanhf() directly */
306 float CDECL
MSVCRT_tanhf( float x
)
310 *(UINT32
*)&x
|= 0x400000;
311 return math_error(_DOMAIN
, "tanhf", x
, 0, x
);
319 /*********************************************************************
323 double CDECL
x87_asin(double);
324 __ASM_GLOBAL_FUNC( x87_asin
,
339 double CDECL
MSVCRT_asin( double x
)
342 unsigned int x87_cw
, sse2_cw
;
343 unsigned int hx
= *(ULONGLONG
*)&x
>> 32;
344 unsigned int ix
= hx
& 0x7fffffff;
346 if (isnan(x
)) return math_error(_DOMAIN
, "asin", x
, 0, x
);
351 __control87_2(0, 0, &x87_cw
, &sse2_cw
);
352 if (!sse2_enabled
|| (x87_cw
& _MCW_EM
) != _MCW_EM
353 || (sse2_cw
& (_MCW_EM
| _MCW_RC
)) != _MCW_EM
)
357 if (isnan(x
)) return x
;
363 /*********************************************************************
366 #if _MSVCR_VER == 0 /* other versions call atan() directly */
367 double CDECL
MSVCRT_atan( double x
)
369 if (isnan(x
)) return math_error(_DOMAIN
, "atan", x
, 0, x
);
374 /*********************************************************************
377 #if _MSVCR_VER == 0 /* other versions call exp() directly */
378 double CDECL
MSVCRT_exp( double x
)
380 if (isnan( x
)) return math_error(_DOMAIN
, "exp", x
, 0, 1.0 + x
);
385 #if defined(__x86_64__) || defined(__i386__)
386 extern short CDECL
_dclass(double x
);
388 static BOOL
sqrt_validate( double *x
, BOOL update_sw
)
390 short c
= _dclass(*x
);
392 if (c
== FP_ZERO
) return FALSE
;
397 *x
= math_error(_DOMAIN
, "sqrt", *x
, 0, *x
);
399 /* set signaling bit */
400 *(ULONGLONG
*)x
|= 0x8000000000000ULL
;
406 *x
= math_error(_DOMAIN
, "sqrt", *x
, 0, ret_nan(update_sw
));
409 if (c
== FP_INFINITE
) return FALSE
;
413 double CDECL
sse2_sqrt(double);
414 __ASM_GLOBAL_FUNC( sse2_sqrt
,
415 "sqrtsd %xmm0, %xmm0\n\t"
420 double CDECL
x87_sqrt(double);
421 __ASM_GLOBAL_FUNC( x87_sqrt
,
429 /*********************************************************************
432 double CDECL
MSVCRT_sqrt( double x
)
435 if (!sqrt_validate(&x
, TRUE
))
439 #elif defined( __i386__ )
440 if (!sqrt_validate(&x
, TRUE
))
449 /*********************************************************************
452 #if _MSVCR_VER < 140 /* other versions call tanh() directly */
453 double CDECL
MSVCRT_tanh( double x
)
457 *(UINT64
*)&x
|= 0x0008000000000000ULL
;
458 return math_error(_DOMAIN
, "tanh", x
, 0, x
);
464 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
466 #define CREATE_FPU_FUNC1(name, call) \
467 __ASM_GLOBAL_FUNC(name, \
469 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
470 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
471 "movl %esp, %ebp\n\t" \
472 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
473 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
474 "fstpl (%esp)\n\t" /* store function argument */ \
476 "movl $1, %ecx\n\t" /* empty FPU stack */ \
480 "and $0x4500, %ax\n\t" \
481 "cmp $0x4100, %ax\n\t" \
483 "fstpl (%esp,%ecx,8)\n\t" \
488 "movl %ecx, -4(%ebp)\n\t" \
489 "call " __ASM_NAME( #call ) "\n\t" \
490 "movl -4(%ebp), %ecx\n\t" \
491 "fstpl (%esp)\n\t" /* save result */ \
492 "3:\n\t" /* restore FPU stack */ \
494 "fldl (%esp,%ecx,8)\n\t" \
495 "cmpl $0, %ecx\n\t" \
498 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
499 __ASM_CFI(".cfi_same_value %ebp\n\t") \
502 #define CREATE_FPU_FUNC2(name, call) \
503 __ASM_GLOBAL_FUNC(name, \
505 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
506 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
507 "movl %esp, %ebp\n\t" \
508 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
509 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
510 "fstpl 8(%esp)\n\t" /* store function argument */ \
514 "movl $2, %ecx\n\t" /* empty FPU stack */ \
518 "and $0x4500, %ax\n\t" \
519 "cmp $0x4100, %ax\n\t" \
521 "fstpl (%esp,%ecx,8)\n\t" \
526 "movl %ecx, -4(%ebp)\n\t" \
527 "call " __ASM_NAME( #call ) "\n\t" \
528 "movl -4(%ebp), %ecx\n\t" \
529 "fstpl 8(%esp)\n\t" /* save result */ \
530 "3:\n\t" /* restore FPU stack */ \
532 "fldl (%esp,%ecx,8)\n\t" \
533 "cmpl $1, %ecx\n\t" \
536 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
537 __ASM_CFI(".cfi_same_value %ebp\n\t") \
540 CREATE_FPU_FUNC1(_CIacos
, acos
)
541 CREATE_FPU_FUNC1(_CIasin
, asin
)
542 CREATE_FPU_FUNC1(_CIatan
, atan
)
543 CREATE_FPU_FUNC2(_CIatan2
, atan2
)
544 CREATE_FPU_FUNC1(_CIcos
, cos
)
545 CREATE_FPU_FUNC1(_CIcosh
, cosh
)
546 CREATE_FPU_FUNC1(_CIexp
, exp
)
547 CREATE_FPU_FUNC2(_CIfmod
, fmod
)
548 CREATE_FPU_FUNC1(_CIlog
, log
)
549 CREATE_FPU_FUNC1(_CIlog10
, log10
)
550 CREATE_FPU_FUNC2(_CIpow
, pow
)
551 CREATE_FPU_FUNC1(_CIsin
, sin
)
552 CREATE_FPU_FUNC1(_CIsinh
, sinh
)
553 CREATE_FPU_FUNC1(_CIsqrt
, sqrt
)
554 CREATE_FPU_FUNC1(_CItan
, tan
)
555 CREATE_FPU_FUNC1(_CItanh
, tanh
)
557 __ASM_GLOBAL_FUNC(_ftol
,
559 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
560 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
561 "movl %esp, %ebp\n\t"
562 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
563 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
565 "mov (%esp), %ax\n\t"
567 "mov %ax, 2(%esp)\n\t"
571 "movl 4(%esp), %eax\n\t"
572 "movl 8(%esp), %edx\n\t"
574 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
575 __ASM_CFI(".cfi_same_value %ebp\n\t")
578 #endif /* (defined(__GNUC__) || defined(__clang__)) && defined(__i386__) */
580 /*********************************************************************
581 * _fpclass (MSVCRT.@)
583 int CDECL
_fpclass(double num
)
585 union { double f
; UINT64 i
; } u
= { num
};
586 int e
= u
.i
>> 52 & 0x7ff;
592 if (u
.i
<< 1) return s
? _FPCLASS_ND
: _FPCLASS_PD
;
593 return s
? _FPCLASS_NZ
: _FPCLASS_PZ
;
595 if (u
.i
<< 12) return ((u
.i
>> 51) & 1) ? _FPCLASS_QNAN
: _FPCLASS_SNAN
;
596 return s
? _FPCLASS_NINF
: _FPCLASS_PINF
;
598 return s
? _FPCLASS_NN
: _FPCLASS_PN
;
602 /*********************************************************************
605 unsigned int CDECL
MSVCRT__rotl(unsigned int num
, int shift
)
608 return (num
<< shift
) | (num
>> (32-shift
));
611 /*********************************************************************
614 __msvcrt_ulong CDECL
MSVCRT__lrotl(__msvcrt_ulong num
, int shift
)
617 return (num
<< shift
) | (num
>> (32-shift
));
620 /*********************************************************************
623 __msvcrt_ulong CDECL
MSVCRT__lrotr(__msvcrt_ulong num
, int shift
)
626 return (num
>> shift
) | (num
<< (32-shift
));
629 /*********************************************************************
632 unsigned int CDECL
MSVCRT__rotr(unsigned int num
, int shift
)
635 return (num
>> shift
) | (num
<< (32-shift
));
638 /*********************************************************************
641 unsigned __int64 CDECL
MSVCRT__rotl64(unsigned __int64 num
, int shift
)
644 return (num
<< shift
) | (num
>> (64-shift
));
647 /*********************************************************************
650 unsigned __int64 CDECL
MSVCRT__rotr64(unsigned __int64 num
, int shift
)
653 return (num
>> shift
) | (num
<< (64-shift
));
656 /*********************************************************************
659 int CDECL
abs( int n
)
661 return n
>= 0 ? n
: -n
;
664 /*********************************************************************
667 __msvcrt_long CDECL
labs( __msvcrt_long n
)
669 return n
>= 0 ? n
: -n
;
673 /*********************************************************************
676 __int64 CDECL
llabs( __int64 n
)
678 return n
>= 0 ? n
: -n
;
683 /*********************************************************************
684 * imaxabs (MSVCR120.@)
686 intmax_t CDECL
imaxabs( intmax_t n
)
688 return n
>= 0 ? n
: -n
;
692 /*********************************************************************
695 __int64 CDECL
_abs64( __int64 n
)
697 return n
>= 0 ? n
: -n
;
700 #if defined(__i386__) || defined(__x86_64__)
701 static void _setfp_sse( unsigned int *cw
, unsigned int cw_mask
,
702 unsigned int *sw
, unsigned int sw_mask
)
704 #if defined(__GNUC__) || defined(__clang__)
705 unsigned long old_fpword
, fpword
;
708 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
711 cw_mask
&= _MCW_EM
| _MCW_RC
| _MCW_DN
;
717 if (fpword
& 0x1) flags
|= _SW_INVALID
;
718 if (fpword
& 0x2) flags
|= _SW_DENORMAL
;
719 if (fpword
& 0x4) flags
|= _SW_ZERODIVIDE
;
720 if (fpword
& 0x8) flags
|= _SW_OVERFLOW
;
721 if (fpword
& 0x10) flags
|= _SW_UNDERFLOW
;
722 if (fpword
& 0x20) flags
|= _SW_INEXACT
;
724 *sw
= (flags
& ~sw_mask
) | (*sw
& sw_mask
);
725 TRACE("sse2 update sw %08x to %08x\n", flags
, *sw
);
727 if (*sw
& _SW_INVALID
) fpword
|= 0x1;
728 if (*sw
& _SW_DENORMAL
) fpword
|= 0x2;
729 if (*sw
& _SW_ZERODIVIDE
) fpword
|= 0x4;
730 if (*sw
& _SW_OVERFLOW
) fpword
|= 0x8;
731 if (*sw
& _SW_UNDERFLOW
) fpword
|= 0x10;
732 if (*sw
& _SW_INEXACT
) fpword
|= 0x20;
739 if (fpword
& 0x80) flags
|= _EM_INVALID
;
740 if (fpword
& 0x100) flags
|= _EM_DENORMAL
;
741 if (fpword
& 0x200) flags
|= _EM_ZERODIVIDE
;
742 if (fpword
& 0x400) flags
|= _EM_OVERFLOW
;
743 if (fpword
& 0x800) flags
|= _EM_UNDERFLOW
;
744 if (fpword
& 0x1000) flags
|= _EM_INEXACT
;
745 switch (fpword
& 0x6000)
747 case 0x6000: flags
|= _RC_UP
|_RC_DOWN
; break;
748 case 0x4000: flags
|= _RC_UP
; break;
749 case 0x2000: flags
|= _RC_DOWN
; break;
751 switch (fpword
& 0x8040)
753 case 0x0040: flags
|= _DN_FLUSH_OPERANDS_SAVE_RESULTS
; break;
754 case 0x8000: flags
|= _DN_SAVE_OPERANDS_FLUSH_RESULTS
; break;
755 case 0x8040: flags
|= _DN_FLUSH
; break;
758 *cw
= (flags
& ~cw_mask
) | (*cw
& cw_mask
);
759 TRACE("sse2 update cw %08x to %08x\n", flags
, *cw
);
761 if (*cw
& _EM_INVALID
) fpword
|= 0x80;
762 if (*cw
& _EM_DENORMAL
) fpword
|= 0x100;
763 if (*cw
& _EM_ZERODIVIDE
) fpword
|= 0x200;
764 if (*cw
& _EM_OVERFLOW
) fpword
|= 0x400;
765 if (*cw
& _EM_UNDERFLOW
) fpword
|= 0x800;
766 if (*cw
& _EM_INEXACT
) fpword
|= 0x1000;
767 switch (*cw
& _MCW_RC
)
769 case _RC_UP
|_RC_DOWN
: fpword
|= 0x6000; break;
770 case _RC_UP
: fpword
|= 0x4000; break;
771 case _RC_DOWN
: fpword
|= 0x2000; break;
773 switch (*cw
& _MCW_DN
)
775 case _DN_FLUSH_OPERANDS_SAVE_RESULTS
: fpword
|= 0x0040; break;
776 case _DN_SAVE_OPERANDS_FLUSH_RESULTS
: fpword
|= 0x8000; break;
777 case _DN_FLUSH
: fpword
|= 0x8040; break;
780 /* clear status word if anything changes */
781 if (fpword
!= old_fpword
&& !sw
)
783 TRACE("sse2 clear status word\n");
788 if (fpword
!= old_fpword
)
789 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
791 FIXME("not implemented\n");
798 static void _setfp( unsigned int *cw
, unsigned int cw_mask
,
799 unsigned int *sw
, unsigned int sw_mask
)
801 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
802 unsigned long oldcw
= 0, newcw
= 0;
803 unsigned long oldsw
= 0, newsw
= 0;
806 cw_mask
&= _MCW_EM
| _MCW_IC
| _MCW_RC
| _MCW_PC
;
811 __asm__
__volatile__( "fstsw %0" : "=m" (newsw
) );
815 if (newsw
& 0x1) flags
|= _SW_INVALID
;
816 if (newsw
& 0x2) flags
|= _SW_DENORMAL
;
817 if (newsw
& 0x4) flags
|= _SW_ZERODIVIDE
;
818 if (newsw
& 0x8) flags
|= _SW_OVERFLOW
;
819 if (newsw
& 0x10) flags
|= _SW_UNDERFLOW
;
820 if (newsw
& 0x20) flags
|= _SW_INEXACT
;
822 *sw
= (flags
& ~sw_mask
) | (*sw
& sw_mask
);
823 TRACE("x86 update sw %08x to %08x\n", flags
, *sw
);
825 if (*sw
& _SW_INVALID
) newsw
|= 0x1;
826 if (*sw
& _SW_DENORMAL
) newsw
|= 0x2;
827 if (*sw
& _SW_ZERODIVIDE
) newsw
|= 0x4;
828 if (*sw
& _SW_OVERFLOW
) newsw
|= 0x8;
829 if (*sw
& _SW_UNDERFLOW
) newsw
|= 0x10;
830 if (*sw
& _SW_INEXACT
) newsw
|= 0x20;
836 __asm__
__volatile__( "fstcw %0" : "=m" (newcw
) );
840 if (newcw
& 0x1) flags
|= _EM_INVALID
;
841 if (newcw
& 0x2) flags
|= _EM_DENORMAL
;
842 if (newcw
& 0x4) flags
|= _EM_ZERODIVIDE
;
843 if (newcw
& 0x8) flags
|= _EM_OVERFLOW
;
844 if (newcw
& 0x10) flags
|= _EM_UNDERFLOW
;
845 if (newcw
& 0x20) flags
|= _EM_INEXACT
;
846 switch (newcw
& 0xc00)
848 case 0xc00: flags
|= _RC_UP
|_RC_DOWN
; break;
849 case 0x800: flags
|= _RC_UP
; break;
850 case 0x400: flags
|= _RC_DOWN
; break;
852 switch (newcw
& 0x300)
854 case 0x0: flags
|= _PC_24
; break;
855 case 0x200: flags
|= _PC_53
; break;
856 case 0x300: flags
|= _PC_64
; break;
858 if (newcw
& 0x1000) flags
|= _IC_AFFINE
;
860 *cw
= (flags
& ~cw_mask
) | (*cw
& cw_mask
);
861 TRACE("x86 update cw %08x to %08x\n", flags
, *cw
);
863 if (*cw
& _EM_INVALID
) newcw
|= 0x1;
864 if (*cw
& _EM_DENORMAL
) newcw
|= 0x2;
865 if (*cw
& _EM_ZERODIVIDE
) newcw
|= 0x4;
866 if (*cw
& _EM_OVERFLOW
) newcw
|= 0x8;
867 if (*cw
& _EM_UNDERFLOW
) newcw
|= 0x10;
868 if (*cw
& _EM_INEXACT
) newcw
|= 0x20;
869 switch (*cw
& _MCW_RC
)
871 case _RC_UP
|_RC_DOWN
: newcw
|= 0xc00; break;
872 case _RC_UP
: newcw
|= 0x800; break;
873 case _RC_DOWN
: newcw
|= 0x400; break;
875 switch (*cw
& _MCW_PC
)
877 case _PC_64
: newcw
|= 0x300; break;
878 case _PC_53
: newcw
|= 0x200; break;
879 case _PC_24
: newcw
|= 0x0; break;
881 if (*cw
& _IC_AFFINE
) newcw
|= 0x1000;
884 if (oldsw
!= newsw
&& (newsw
& 0x3f))
893 DWORD instruction_pointer
;
903 __asm__
__volatile__( "fnstenv %0" : "=m" (fenv
) );
904 fenv
.control_word
= newcw
;
905 fenv
.status_word
= newsw
;
906 __asm__
__volatile__( "fldenv %0" : : "m" (fenv
) : "st", "st(1)",
907 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
912 __asm__
__volatile__( "fnclex" );
914 __asm__
__volatile__( "fldcw %0" : : "m" (newcw
) );
915 #elif defined(__x86_64__)
916 _setfp_sse(cw
, cw_mask
, sw
, sw_mask
);
917 #elif defined(__aarch64__)
918 ULONG_PTR old_fpsr
= 0, fpsr
= 0, old_fpcr
= 0, fpcr
= 0;
921 cw_mask
&= _MCW_EM
| _MCW_RC
;
926 __asm__
__volatile__( "mrs %0, fpsr" : "=r" (fpsr
) );
930 if (fpsr
& 0x1) flags
|= _SW_INVALID
;
931 if (fpsr
& 0x2) flags
|= _SW_ZERODIVIDE
;
932 if (fpsr
& 0x4) flags
|= _SW_OVERFLOW
;
933 if (fpsr
& 0x8) flags
|= _SW_UNDERFLOW
;
934 if (fpsr
& 0x10) flags
|= _SW_INEXACT
;
935 if (fpsr
& 0x80) flags
|= _SW_DENORMAL
;
937 *sw
= (flags
& ~sw_mask
) | (*sw
& sw_mask
);
938 TRACE("aarch64 update sw %08x to %08x\n", flags
, *sw
);
940 if (*sw
& _SW_INVALID
) fpsr
|= 0x1;
941 if (*sw
& _SW_ZERODIVIDE
) fpsr
|= 0x2;
942 if (*sw
& _SW_OVERFLOW
) fpsr
|= 0x4;
943 if (*sw
& _SW_UNDERFLOW
) fpsr
|= 0x8;
944 if (*sw
& _SW_INEXACT
) fpsr
|= 0x10;
945 if (*sw
& _SW_DENORMAL
) fpsr
|= 0x80;
951 __asm__
__volatile__( "mrs %0, fpcr" : "=r" (fpcr
) );
955 if (!(fpcr
& 0x100)) flags
|= _EM_INVALID
;
956 if (!(fpcr
& 0x200)) flags
|= _EM_ZERODIVIDE
;
957 if (!(fpcr
& 0x400)) flags
|= _EM_OVERFLOW
;
958 if (!(fpcr
& 0x800)) flags
|= _EM_UNDERFLOW
;
959 if (!(fpcr
& 0x1000)) flags
|= _EM_INEXACT
;
960 if (!(fpcr
& 0x8000)) flags
|= _EM_DENORMAL
;
961 switch (fpcr
& 0xc00000)
963 case 0x400000: flags
|= _RC_UP
; break;
964 case 0x800000: flags
|= _RC_DOWN
; break;
965 case 0xc00000: flags
|= _RC_CHOP
; break;
968 *cw
= (flags
& ~cw_mask
) | (*cw
& cw_mask
);
969 TRACE("aarch64 update cw %08x to %08x\n", flags
, *cw
);
971 if (!(*cw
& _EM_INVALID
)) fpcr
|= 0x100;
972 if (!(*cw
& _EM_ZERODIVIDE
)) fpcr
|= 0x200;
973 if (!(*cw
& _EM_OVERFLOW
)) fpcr
|= 0x400;
974 if (!(*cw
& _EM_UNDERFLOW
)) fpcr
|= 0x800;
975 if (!(*cw
& _EM_INEXACT
)) fpcr
|= 0x1000;
976 if (!(*cw
& _EM_DENORMAL
)) fpcr
|= 0x8000;
977 switch (*cw
& _MCW_RC
)
979 case _RC_CHOP
: fpcr
|= 0xc00000; break;
980 case _RC_UP
: fpcr
|= 0x400000; break;
981 case _RC_DOWN
: fpcr
|= 0x800000; break;
985 /* mask exceptions if needed */
986 if (old_fpcr
!= fpcr
&& ~(old_fpcr
>> 8) & fpsr
& 0x9f != fpsr
& 0x9f)
988 ULONG_PTR mask
= fpcr
& ~0x9f00;
989 __asm__
__volatile__( "msr fpcr, %0" :: "r" (mask
) );
992 if (old_fpsr
!= fpsr
)
993 __asm__
__volatile__( "msr fpsr, %0" :: "r" (fpsr
) );
994 if (old_fpcr
!= fpcr
)
995 __asm__
__volatile__( "msr fpcr, %0" :: "r" (fpcr
) );
996 #elif defined(__arm__) && !defined(__SOFTFP__)
997 DWORD old_fpscr
, fpscr
;
1000 __asm__
__volatile__( "vmrs %0, fpscr" : "=r" (fpscr
) );
1003 cw_mask
&= _MCW_EM
| _MCW_RC
;
1009 if (fpscr
& 0x1) flags
|= _SW_INVALID
;
1010 if (fpscr
& 0x2) flags
|= _SW_ZERODIVIDE
;
1011 if (fpscr
& 0x4) flags
|= _SW_OVERFLOW
;
1012 if (fpscr
& 0x8) flags
|= _SW_UNDERFLOW
;
1013 if (fpscr
& 0x10) flags
|= _SW_INEXACT
;
1014 if (fpscr
& 0x80) flags
|= _SW_DENORMAL
;
1016 *sw
= (flags
& ~sw_mask
) | (*sw
& sw_mask
);
1017 TRACE("arm update sw %08x to %08x\n", flags
, *sw
);
1019 if (*sw
& _SW_INVALID
) fpscr
|= 0x1;
1020 if (*sw
& _SW_ZERODIVIDE
) fpscr
|= 0x2;
1021 if (*sw
& _SW_OVERFLOW
) fpscr
|= 0x4;
1022 if (*sw
& _SW_UNDERFLOW
) fpscr
|= 0x8;
1023 if (*sw
& _SW_INEXACT
) fpscr
|= 0x10;
1024 if (*sw
& _SW_DENORMAL
) fpscr
|= 0x80;
1031 if (!(fpscr
& 0x100)) flags
|= _EM_INVALID
;
1032 if (!(fpscr
& 0x200)) flags
|= _EM_ZERODIVIDE
;
1033 if (!(fpscr
& 0x400)) flags
|= _EM_OVERFLOW
;
1034 if (!(fpscr
& 0x800)) flags
|= _EM_UNDERFLOW
;
1035 if (!(fpscr
& 0x1000)) flags
|= _EM_INEXACT
;
1036 if (!(fpscr
& 0x8000)) flags
|= _EM_DENORMAL
;
1037 switch (fpscr
& 0xc00000)
1039 case 0x400000: flags
|= _RC_UP
; break;
1040 case 0x800000: flags
|= _RC_DOWN
; break;
1041 case 0xc00000: flags
|= _RC_CHOP
; break;
1044 *cw
= (flags
& ~cw_mask
) | (*cw
& cw_mask
);
1045 TRACE("arm update cw %08x to %08x\n", flags
, *cw
);
1046 fpscr
&= ~0xc09f00ul
;
1047 if (!(*cw
& _EM_INVALID
)) fpscr
|= 0x100;
1048 if (!(*cw
& _EM_ZERODIVIDE
)) fpscr
|= 0x200;
1049 if (!(*cw
& _EM_OVERFLOW
)) fpscr
|= 0x400;
1050 if (!(*cw
& _EM_UNDERFLOW
)) fpscr
|= 0x800;
1051 if (!(*cw
& _EM_INEXACT
)) fpscr
|= 0x1000;
1052 if (!(*cw
& _EM_DENORMAL
)) fpscr
|= 0x8000;
1053 switch (*cw
& _MCW_RC
)
1055 case _RC_CHOP
: fpscr
|= 0xc00000; break;
1056 case _RC_UP
: fpscr
|= 0x400000; break;
1057 case _RC_DOWN
: fpscr
|= 0x800000; break;
1061 if (old_fpscr
!= fpscr
)
1062 __asm__
__volatile__( "vmsr fpscr, %0" :: "r" (fpscr
) );
1064 FIXME("not implemented\n");
1070 /**********************************************************************
1071 * _statusfp2 (MSVCR80.@)
1073 #if defined(__i386__)
1074 void CDECL
_statusfp2( unsigned int *x86_sw
, unsigned int *sse2_sw
)
1077 _setfp(NULL
, 0, x86_sw
, 0);
1078 if (!sse2_sw
) return;
1080 _setfp_sse(NULL
, 0, sse2_sw
, 0);
1085 /**********************************************************************
1086 * _statusfp (MSVCRT.@)
1088 unsigned int CDECL
_statusfp(void)
1090 unsigned int flags
= 0;
1091 #if defined(__i386__)
1092 unsigned int x86_sw
, sse2_sw
;
1094 _statusfp2( &x86_sw
, &sse2_sw
);
1095 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1096 flags
= x86_sw
| sse2_sw
;
1098 _setfp(NULL
, 0, &flags
, 0);
1103 /*********************************************************************
1104 * _clearfp (MSVCRT.@)
1106 unsigned int CDECL
_clearfp(void)
1108 unsigned int flags
= 0;
1110 _setfp(NULL
, 0, &flags
, _MCW_EM
);
1113 unsigned int sse_sw
= 0;
1115 _setfp_sse(NULL
, 0, &sse_sw
, _MCW_EM
);
1119 _setfp(NULL
, 0, &flags
, _MCW_EM
);
1124 /*********************************************************************
1125 * __fpecode (MSVCRT.@)
1127 int * CDECL
__fpecode(void)
1129 return &msvcrt_get_thread_data()->fpecode
;
1132 /*********************************************************************
1135 double CDECL
ldexp(double num
, int exp
)
1137 double z
= scalbn(num
, exp
);
1139 if (isfinite(num
) && !isfinite(z
))
1140 return math_error(_OVERFLOW
, "ldexp", num
, exp
, z
);
1141 if (num
&& isfinite(num
) && !z
)
1142 return math_error(_UNDERFLOW
, "ldexp", num
, exp
, z
);
1146 /*********************************************************************
1149 double CDECL
_cabs(struct _complex num
)
1151 return sqrt(num
.x
* num
.x
+ num
.y
* num
.y
);
1154 /*********************************************************************
1155 * _chgsign (MSVCRT.@)
1157 double CDECL
_chgsign(double num
)
1159 union { double f
; UINT64 i
; } u
= { num
};
1164 /*********************************************************************
1165 * __control87_2 (MSVCR80.@)
1167 * Not exported by native msvcrt, added in msvcr80.
1170 int CDECL
__control87_2( unsigned int newval
, unsigned int mask
,
1171 unsigned int *x86_cw
, unsigned int *sse2_cw
)
1176 _setfp(x86_cw
, mask
, NULL
, 0);
1179 if (!sse2_cw
) return 1;
1184 _setfp_sse(sse2_cw
, mask
, NULL
, 0);
1192 /*********************************************************************
1193 * _control87 (MSVCRT.@)
1195 unsigned int CDECL
_control87(unsigned int newval
, unsigned int mask
)
1197 unsigned int flags
= 0;
1198 #if defined(__i386__) && (_MSVCR_VER == 0 || _MSVCR_VER >= 80)
1199 unsigned int sse2_cw
;
1201 __control87_2( newval
, mask
, &flags
, &sse2_cw
);
1205 if ((flags
^ sse2_cw
) & (_MCW_EM
| _MCW_RC
)) flags
|= _EM_AMBIGUOUS
;
1210 _setfp(&flags
, mask
, NULL
, 0);
1215 /*********************************************************************
1216 * _controlfp (MSVCRT.@)
1218 unsigned int CDECL
_controlfp(unsigned int newval
, unsigned int mask
)
1220 return _control87( newval
, mask
& ~_EM_DENORMAL
);
1223 /*********************************************************************
1224 * _set_controlfp (MSVCRT.@)
1226 void CDECL
_set_controlfp( unsigned int newval
, unsigned int mask
)
1228 _controlfp( newval
, mask
);
1231 /*********************************************************************
1232 * _controlfp_s (MSVCRT.@)
1234 int CDECL
_controlfp_s(unsigned int *cur
, unsigned int newval
, unsigned int mask
)
1236 static const unsigned int all_flags
= (_MCW_EM
| _MCW_IC
| _MCW_RC
|
1240 if (!MSVCRT_CHECK_PMT( !(newval
& mask
& ~all_flags
) ))
1242 if (cur
) *cur
= _controlfp( 0, 0 ); /* retrieve it anyway */
1245 val
= _controlfp( newval
, mask
);
1246 if (cur
) *cur
= val
;
1250 #if _MSVCR_VER >= 140 && (defined(__i386__) || defined(__x86_64__))
1253 FENV_X_INVALID
= 0x00100010,
1254 FENV_X_DENORMAL
= 0x00200020,
1255 FENV_X_ZERODIVIDE
= 0x00080008,
1256 FENV_X_OVERFLOW
= 0x00040004,
1257 FENV_X_UNDERFLOW
= 0x00020002,
1258 FENV_X_INEXACT
= 0x00010001,
1259 FENV_X_AFFINE
= 0x00004000,
1260 FENV_X_UP
= 0x00800200,
1261 FENV_X_DOWN
= 0x00400100,
1262 FENV_X_24
= 0x00002000,
1263 FENV_X_53
= 0x00001000,
1264 FENV_Y_INVALID
= 0x10000010,
1265 FENV_Y_DENORMAL
= 0x20000020,
1266 FENV_Y_ZERODIVIDE
= 0x08000008,
1267 FENV_Y_OVERFLOW
= 0x04000004,
1268 FENV_Y_UNDERFLOW
= 0x02000002,
1269 FENV_Y_INEXACT
= 0x01000001,
1270 FENV_Y_UP
= 0x80000200,
1271 FENV_Y_DOWN
= 0x40000100,
1272 FENV_Y_FLUSH
= 0x00000400,
1273 FENV_Y_FLUSH_SAVE
= 0x00000800
1276 /* encodes x87/sse control/status word in ulong */
1277 static __msvcrt_ulong
fenv_encode(unsigned int x
, unsigned int y
)
1279 __msvcrt_ulong ret
= 0;
1282 if (x
& _EM_INVALID
) ret
|= FENV_X_INVALID
;
1283 if (x
& _EM_DENORMAL
) ret
|= FENV_X_DENORMAL
;
1284 if (x
& _EM_ZERODIVIDE
) ret
|= FENV_X_ZERODIVIDE
;
1285 if (x
& _EM_OVERFLOW
) ret
|= FENV_X_OVERFLOW
;
1286 if (x
& _EM_UNDERFLOW
) ret
|= FENV_X_UNDERFLOW
;
1287 if (x
& _EM_INEXACT
) ret
|= FENV_X_INEXACT
;
1288 if (x
& _IC_AFFINE
) ret
|= FENV_X_AFFINE
;
1289 if (x
& _RC_UP
) ret
|= FENV_X_UP
;
1290 if (x
& _RC_DOWN
) ret
|= FENV_X_DOWN
;
1291 if (x
& _PC_24
) ret
|= FENV_X_24
;
1292 if (x
& _PC_53
) ret
|= FENV_X_53
;
1294 x
&= ~(_MCW_EM
| _MCW_IC
| _MCW_RC
| _MCW_PC
);
1296 if (y
& _EM_INVALID
) ret
|= FENV_Y_INVALID
;
1297 if (y
& _EM_DENORMAL
) ret
|= FENV_Y_DENORMAL
;
1298 if (y
& _EM_ZERODIVIDE
) ret
|= FENV_Y_ZERODIVIDE
;
1299 if (y
& _EM_OVERFLOW
) ret
|= FENV_Y_OVERFLOW
;
1300 if (y
& _EM_UNDERFLOW
) ret
|= FENV_Y_UNDERFLOW
;
1301 if (y
& _EM_INEXACT
) ret
|= FENV_Y_INEXACT
;
1302 if (y
& _RC_UP
) ret
|= FENV_Y_UP
;
1303 if (y
& _RC_DOWN
) ret
|= FENV_Y_DOWN
;
1304 if (y
& _DN_FLUSH
) ret
|= FENV_Y_FLUSH
;
1305 if (y
& _DN_FLUSH_OPERANDS_SAVE_RESULTS
) ret
|= FENV_Y_FLUSH_SAVE
;
1306 y
&= ~(_MCW_EM
| _MCW_IC
| _MCW_RC
| _MCW_DN
);
1308 if(x
|| y
) FIXME("unsupported flags: %x, %x\n", x
, y
);
1312 /* decodes x87/sse control/status word, returns FALSE on error */
1313 static BOOL
fenv_decode(__msvcrt_ulong enc
, unsigned int *x
, unsigned int *y
)
1316 if ((enc
& FENV_X_INVALID
) == FENV_X_INVALID
) *x
|= _EM_INVALID
;
1317 if ((enc
& FENV_X_DENORMAL
) == FENV_X_DENORMAL
) *x
|= _EM_DENORMAL
;
1318 if ((enc
& FENV_X_ZERODIVIDE
) == FENV_X_ZERODIVIDE
) *x
|= _EM_ZERODIVIDE
;
1319 if ((enc
& FENV_X_OVERFLOW
) == FENV_X_OVERFLOW
) *x
|= _EM_OVERFLOW
;
1320 if ((enc
& FENV_X_UNDERFLOW
) == FENV_X_UNDERFLOW
) *x
|= _EM_UNDERFLOW
;
1321 if ((enc
& FENV_X_INEXACT
) == FENV_X_INEXACT
) *x
|= _EM_INEXACT
;
1322 if ((enc
& FENV_X_AFFINE
) == FENV_X_AFFINE
) *x
|= _IC_AFFINE
;
1323 if ((enc
& FENV_X_UP
) == FENV_X_UP
) *x
|= _RC_UP
;
1324 if ((enc
& FENV_X_DOWN
) == FENV_X_DOWN
) *x
|= _RC_DOWN
;
1325 if ((enc
& FENV_X_24
) == FENV_X_24
) *x
|= _PC_24
;
1326 if ((enc
& FENV_X_53
) == FENV_X_53
) *x
|= _PC_53
;
1328 if ((enc
& FENV_Y_INVALID
) == FENV_Y_INVALID
) *y
|= _EM_INVALID
;
1329 if ((enc
& FENV_Y_DENORMAL
) == FENV_Y_DENORMAL
) *y
|= _EM_DENORMAL
;
1330 if ((enc
& FENV_Y_ZERODIVIDE
) == FENV_Y_ZERODIVIDE
) *y
|= _EM_ZERODIVIDE
;
1331 if ((enc
& FENV_Y_OVERFLOW
) == FENV_Y_OVERFLOW
) *y
|= _EM_OVERFLOW
;
1332 if ((enc
& FENV_Y_UNDERFLOW
) == FENV_Y_UNDERFLOW
) *y
|= _EM_UNDERFLOW
;
1333 if ((enc
& FENV_Y_INEXACT
) == FENV_Y_INEXACT
) *y
|= _EM_INEXACT
;
1334 if ((enc
& FENV_Y_UP
) == FENV_Y_UP
) *y
|= _RC_UP
;
1335 if ((enc
& FENV_Y_DOWN
) == FENV_Y_DOWN
) *y
|= _RC_DOWN
;
1336 if ((enc
& FENV_Y_FLUSH
) == FENV_Y_FLUSH
) *y
|= _DN_FLUSH
;
1337 if ((enc
& FENV_Y_FLUSH_SAVE
) == FENV_Y_FLUSH_SAVE
) *y
|= _DN_FLUSH_OPERANDS_SAVE_RESULTS
;
1339 if (fenv_encode(*x
, *y
) != enc
)
1341 WARN("can't decode: %lx\n", enc
);
1346 #elif _MSVCR_VER >= 120
1347 static __msvcrt_ulong
fenv_encode(unsigned int x
, unsigned int y
)
1349 if (y
& _EM_DENORMAL
)
1350 y
= (y
& ~_EM_DENORMAL
) | 0x20;
1355 static BOOL
fenv_decode(__msvcrt_ulong enc
, unsigned int *x
, unsigned int *y
)
1358 enc
= (enc
& ~0x20) | _EM_DENORMAL
;
1366 /*********************************************************************
1367 * fegetenv (MSVCR120.@)
1369 int CDECL
fegetenv(fenv_t
*env
)
1371 #if _MSVCR_VER>=140 && defined(__i386__)
1372 unsigned int x87
, sse
;
1373 __control87_2(0, 0, &x87
, &sse
);
1374 env
->_Fe_ctl
= fenv_encode(x87
, sse
);
1375 _statusfp2(&x87
, &sse
);
1376 env
->_Fe_stat
= fenv_encode(x87
, sse
);
1377 #elif _MSVCR_VER>=140
1378 env
->_Fe_ctl
= fenv_encode(0, _control87(0, 0));
1379 env
->_Fe_stat
= fenv_encode(0, _statusfp());
1381 env
->_Fe_ctl
= _controlfp(0, 0) & (_EM_INEXACT
| _EM_UNDERFLOW
|
1382 _EM_OVERFLOW
| _EM_ZERODIVIDE
| _EM_INVALID
| _MCW_RC
);
1383 env
->_Fe_stat
= _statusfp();
1388 /*********************************************************************
1389 * feupdateenv (MSVCR120.@)
1391 int CDECL
feupdateenv(const fenv_t
*env
)
1395 set
._Fe_ctl
= env
->_Fe_ctl
;
1396 set
._Fe_stat
|= env
->_Fe_stat
;
1397 return fesetenv(&set
);
1400 /*********************************************************************
1401 * fetestexcept (MSVCR120.@)
1403 int CDECL
fetestexcept(int flags
)
1405 return _statusfp() & flags
;
1408 /*********************************************************************
1409 * fesetexceptflag (MSVCR120.@)
1411 int CDECL
fesetexceptflag(const fexcept_t
*status
, int excepts
)
1415 excepts
&= FE_ALL_EXCEPT
;
1420 env
._Fe_stat
&= ~fenv_encode(excepts
, excepts
);
1421 env
._Fe_stat
|= *status
& fenv_encode(excepts
, excepts
);
1422 return fesetenv(&env
);
1425 /*********************************************************************
1426 * feraiseexcept (MSVCR120.@)
1428 int CDECL
feraiseexcept(int flags
)
1432 flags
&= FE_ALL_EXCEPT
;
1434 env
._Fe_stat
|= fenv_encode(flags
, flags
);
1435 return fesetenv(&env
);
1438 /*********************************************************************
1439 * feclearexcept (MSVCR120.@)
1441 int CDECL
feclearexcept(int flags
)
1446 flags
&= FE_ALL_EXCEPT
;
1447 env
._Fe_stat
&= ~fenv_encode(flags
, flags
);
1448 return fesetenv(&env
);
1451 /*********************************************************************
1452 * fegetexceptflag (MSVCR120.@)
1454 int CDECL
fegetexceptflag(fexcept_t
*status
, int excepts
)
1456 #if _MSVCR_VER>=140 && defined(__i386__)
1457 unsigned int x87
, sse
;
1458 _statusfp2(&x87
, &sse
);
1459 *status
= fenv_encode(x87
& excepts
, sse
& excepts
);
1461 *status
= fenv_encode(0, _statusfp() & excepts
);
1468 /*********************************************************************
1469 * __fpe_flt_rounds (UCRTBASE.@)
1471 int CDECL
__fpe_flt_rounds(void)
1473 unsigned int fpc
= _controlfp(0, 0) & _RC_CHOP
;
1478 case _RC_CHOP
: return 0;
1479 case _RC_NEAR
: return 1;
1480 case _RC_UP
: return 2;
1488 /*********************************************************************
1489 * fegetround (MSVCR120.@)
1491 int CDECL
fegetround(void)
1493 return _controlfp(0, 0) & _MCW_RC
;
1496 /*********************************************************************
1497 * fesetround (MSVCR120.@)
1499 int CDECL
fesetround(int round_mode
)
1501 if (round_mode
& (~_MCW_RC
))
1503 _controlfp(round_mode
, _MCW_RC
);
1507 #endif /* _MSVCR_VER>=120 */
1509 /*********************************************************************
1510 * _finite (MSVCRT.@)
1512 int CDECL
_finite(double num
)
1514 union { double f
; UINT64 i
; } u
= { num
};
1515 return (u
.i
& ~0ull >> 1) < 0x7ffull
<< 52;
1518 /*********************************************************************
1519 * _fpreset (MSVCRT.@)
1521 void CDECL
_fpreset(void)
1523 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
1524 const unsigned int x86_cw
= 0x27f;
1525 __asm__
__volatile__( "fninit; fldcw %0" : : "m" (x86_cw
) );
1528 unsigned int cw
= _MCW_EM
, sw
= 0;
1529 _setfp_sse(&cw
, ~0, &sw
, ~0);
1532 unsigned int cw
= _MCW_EM
, sw
= 0;
1533 _setfp(&cw
, ~0, &sw
, ~0);
1538 /*********************************************************************
1539 * fesetenv (MSVCR120.@)
1541 int CDECL
fesetenv(const fenv_t
*env
)
1543 unsigned int x87_cw
, cw
, x87_stat
, stat
;
1546 TRACE( "(%p)\n", env
);
1548 if (!env
->_Fe_ctl
&& !env
->_Fe_stat
) {
1553 if (!fenv_decode(env
->_Fe_ctl
, &x87_cw
, &cw
))
1555 if (!fenv_decode(env
->_Fe_stat
, &x87_stat
, &stat
))
1558 #if _MSVCR_VER >= 140
1561 mask
= _EM_INEXACT
| _EM_UNDERFLOW
| _EM_OVERFLOW
1562 | _EM_ZERODIVIDE
| _EM_INVALID
| _MCW_RC
;
1566 _setfp(&x87_cw
, mask
, &x87_stat
, ~0);
1568 _setfp_sse(&cw
, mask
, &stat
, ~0);
1571 _setfp(&cw
, mask
, &stat
, ~0);
1577 /*********************************************************************
1580 int CDECL
_isnan(double num
)
1582 union { double f
; UINT64 i
; } u
= { num
};
1583 return (u
.i
& ~0ull >> 1) > 0x7ffull
<< 52;
1588 /*********************************************************************
1591 double CDECL
MSVCRT_rint(double x
)
1596 cw
= _controlfp(0, 0);
1597 if ((cw
& _MCW_PC
) != _PC_53
)
1598 _controlfp(_PC_53
, _MCW_PC
);
1600 if ((cw
& _MCW_PC
) != _PC_53
)
1601 _controlfp(cw
, _MCW_PC
);
1605 /*********************************************************************
1606 * _nearbyint (MSVCR120.@)
1608 * Based on musl: src/math/nearbyteint.c
1610 double CDECL
nearbyint(double x
)
1612 BOOL update_cw
, update_sw
;
1613 unsigned int cw
, sw
;
1615 _setfp(&cw
, 0, &sw
, 0);
1616 update_cw
= !(cw
& _EM_INEXACT
);
1617 update_sw
= !(sw
& _SW_INEXACT
);
1621 _setfp(&cw
, _EM_INEXACT
, NULL
, 0);
1624 if (update_cw
|| update_sw
)
1628 _setfp(update_cw
? &cw
: NULL
, _EM_INEXACT
,
1629 update_sw
? &sw
: NULL
, _SW_INEXACT
);
1634 /*********************************************************************
1635 * _nearbyintf (MSVCR120.@)
1637 * Based on musl: src/math/nearbyteintf.c
1639 float CDECL
nearbyintf(float x
)
1641 BOOL update_cw
, update_sw
;
1642 unsigned int cw
, sw
;
1644 _setfp(&cw
, 0, &sw
, 0);
1645 update_cw
= !(cw
& _EM_INEXACT
);
1646 update_sw
= !(sw
& _SW_INEXACT
);
1650 _setfp(&cw
, _EM_INEXACT
, NULL
, 0);
1653 if (update_cw
|| update_sw
)
1657 _setfp(update_cw
? &cw
: NULL
, _EM_INEXACT
,
1658 update_sw
? &sw
: NULL
, _SW_INEXACT
);
1663 #endif /* _MSVCR_VER>=120 */
1665 /*********************************************************************
1668 char * CDECL
_ecvt( double number
, int ndigits
, int *decpt
, int *sign
)
1671 thread_data_t
*data
= msvcrt_get_thread_data();
1672 /* FIXME: check better for overflow (native supports over 300 chars) */
1673 ndigits
= min( ndigits
, 80 - 8); /* 8 : space for sign, dec point, "e",
1674 * 4 for exponent and one for
1675 * terminating '\0' */
1676 if (!data
->efcvt_buffer
)
1677 data
->efcvt_buffer
= malloc( 80 ); /* ought to be enough */
1679 /* handle cases with zero ndigits or less */
1681 if( prec
< 1) prec
= 2;
1682 len
= _snprintf(data
->efcvt_buffer
, 80, "%.*le", prec
- 1, number
);
1684 if (data
->efcvt_buffer
[0] == '-') {
1685 memmove( data
->efcvt_buffer
, data
->efcvt_buffer
+ 1, len
-- );
1689 /* take the decimal "point away */
1691 memmove( data
->efcvt_buffer
+ 1, data
->efcvt_buffer
+ 2, len
- 1 );
1692 /* take the exponential "e" out */
1693 data
->efcvt_buffer
[ prec
] = '\0';
1694 /* read the exponent */
1695 sscanf( data
->efcvt_buffer
+ prec
+ 1, "%d", decpt
);
1697 /* adjust for some border cases */
1698 if( data
->efcvt_buffer
[0] == '0')/* value is zero */
1700 /* handle cases with zero ndigits or less */
1702 if( data
->efcvt_buffer
[ 0] >= '5')
1704 data
->efcvt_buffer
[ 0] = '\0';
1706 TRACE("out=\"%s\"\n",data
->efcvt_buffer
);
1707 return data
->efcvt_buffer
;
1710 /*********************************************************************
1711 * _ecvt_s (MSVCRT.@)
1713 int CDECL
_ecvt_s( char *buffer
, size_t length
, double number
, int ndigits
, int *decpt
, int *sign
)
1718 if (!MSVCRT_CHECK_PMT(buffer
!= NULL
)) return EINVAL
;
1719 if (!MSVCRT_CHECK_PMT(decpt
!= NULL
)) return EINVAL
;
1720 if (!MSVCRT_CHECK_PMT(sign
!= NULL
)) return EINVAL
;
1721 if (!MSVCRT_CHECK_PMT_ERR( length
> 2, ERANGE
)) return ERANGE
;
1722 if (!MSVCRT_CHECK_PMT_ERR(ndigits
< (int)length
- 1, ERANGE
)) return ERANGE
;
1724 /* handle cases with zero ndigits or less */
1726 if( prec
< 1) prec
= 2;
1727 result
= malloc(prec
+ 8);
1729 len
= _snprintf(result
, prec
+ 8, "%.*le", prec
- 1, number
);
1730 if (result
[0] == '-') {
1731 memmove( result
, result
+ 1, len
-- );
1735 /* take the decimal "point away */
1737 memmove( result
+ 1, result
+ 2, len
- 1 );
1738 /* take the exponential "e" out */
1739 result
[ prec
] = '\0';
1740 /* read the exponent */
1741 sscanf( result
+ prec
+ 1, "%d", decpt
);
1743 /* adjust for some border cases */
1744 if( result
[0] == '0')/* value is zero */
1746 /* handle cases with zero ndigits or less */
1748 if( result
[ 0] >= '5')
1752 memcpy( buffer
, result
, max(ndigits
+ 1, 1) );
1757 /***********************************************************************
1760 char * CDECL
_fcvt( double number
, int ndigits
, int *decpt
, int *sign
)
1762 thread_data_t
*data
= msvcrt_get_thread_data();
1763 int stop
, dec1
, dec2
;
1764 char *ptr1
, *ptr2
, *first
;
1765 char buf
[80]; /* ought to be enough */
1766 char decimal_separator
= get_locinfo()->lconv
->decimal_point
[0];
1768 if (!data
->efcvt_buffer
)
1769 data
->efcvt_buffer
= malloc( 80 ); /* ought to be enough */
1771 stop
= _snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
1773 ptr2
= data
->efcvt_buffer
;
1783 /* For numbers below the requested resolution, work out where
1784 the decimal point will be rather than finding it in the string */
1785 if (number
< 1.0 && number
> 0.0) {
1786 dec2
= log10(number
+ 1e-10);
1787 if (-dec2
<= ndigits
) dec2
= 0;
1790 /* If requested digits is zero or less, we will need to truncate
1791 * the returned string */
1796 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
1797 while (*ptr1
!= '\0' && *ptr1
!= decimal_separator
) {
1798 if (!first
) first
= ptr2
;
1799 if ((ptr1
- buf
) < stop
) {
1810 while (*ptr1
== '0') { /* Process leading zeroes */
1815 while (*ptr1
!= '\0') {
1816 if (!first
) first
= ptr2
;
1823 /* We never found a non-zero digit, then our number is either
1824 * smaller than the requested precision, or 0.0 */
1829 first
= data
->efcvt_buffer
;
1834 *decpt
= dec2
? dec2
: dec1
;
1838 /***********************************************************************
1839 * _fcvt_s (MSVCRT.@)
1841 int CDECL
_fcvt_s(char* outbuffer
, size_t size
, double number
, int ndigits
, int *decpt
, int *sign
)
1843 int stop
, dec1
, dec2
;
1844 char *ptr1
, *ptr2
, *first
;
1845 char buf
[80]; /* ought to be enough */
1846 char decimal_separator
= get_locinfo()->lconv
->decimal_point
[0];
1848 if (!outbuffer
|| !decpt
|| !sign
|| size
== 0)
1854 stop
= _snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
1866 /* For numbers below the requested resolution, work out where
1867 the decimal point will be rather than finding it in the string */
1868 if (number
< 1.0 && number
> 0.0) {
1869 dec2
= log10(number
+ 1e-10);
1870 if (-dec2
<= ndigits
) dec2
= 0;
1873 /* If requested digits is zero or less, we will need to truncate
1874 * the returned string */
1879 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
1880 while (*ptr1
!= '\0' && *ptr1
!= decimal_separator
) {
1881 if (!first
) first
= ptr2
;
1882 if ((ptr1
- buf
) < stop
) {
1896 while (*ptr1
== '0') { /* Process leading zeroes */
1897 if (number
== 0.0 && size
> 1) {
1905 while (*ptr1
!= '\0') {
1906 if (!first
) first
= ptr2
;
1916 /* We never found a non-zero digit, then our number is either
1917 * smaller than the requested precision, or 0.0 */
1918 if (!first
&& (number
<= 0.0))
1921 *decpt
= dec2
? dec2
: dec1
;
1925 /***********************************************************************
1928 char * CDECL
_gcvt( double number
, int ndigit
, char *buff
)
1940 sprintf(buff
, "%.*g", ndigit
, number
);
1944 /***********************************************************************
1945 * _gcvt_s (MSVCRT.@)
1947 int CDECL
_gcvt_s(char *buff
, size_t size
, double number
, int digits
)
1956 if( digits
<0 || digits
>=size
) {
1964 len
= _scprintf("%.*g", digits
, number
);
1971 sprintf(buff
, "%.*g", digits
, number
);
1975 #include <stdlib.h> /* div_t, ldiv_t */
1977 /*********************************************************************
1980 * [i386] Windows binary compatible - returns the struct in eax/edx.
1983 unsigned __int64 CDECL
div(int num
, int denom
)
1987 unsigned __int64 uint64
;
1990 ret
.div
.quot
= num
/ denom
;
1991 ret
.div
.rem
= num
% denom
;
1995 /*********************************************************************
1998 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2000 div_t CDECL
div(int num
, int denom
)
2004 ret
.quot
= num
/ denom
;
2005 ret
.rem
= num
% denom
;
2008 #endif /* ifdef __i386__ */
2011 /*********************************************************************
2014 * [i386] Windows binary compatible - returns the struct in eax/edx.
2017 unsigned __int64 CDECL
ldiv(__msvcrt_long num
, __msvcrt_long denom
)
2021 unsigned __int64 uint64
;
2024 ret
.ldiv
.quot
= num
/ denom
;
2025 ret
.ldiv
.rem
= num
% denom
;
2029 /*********************************************************************
2032 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2034 ldiv_t CDECL
ldiv(__msvcrt_long num
, __msvcrt_long denom
)
2038 ret
.quot
= num
/ denom
;
2039 ret
.rem
= num
% denom
;
2042 #endif /* ifdef __i386__ */
2045 /*********************************************************************
2046 * lldiv (MSVCR100.@)
2048 lldiv_t CDECL
lldiv(__int64 num
, __int64 denom
)
2052 ret
.quot
= num
/ denom
;
2053 ret
.rem
= num
% denom
;
2061 /*********************************************************************
2062 * _adjust_fdiv (MSVCRT.@)
2063 * Used by the MSVC compiler to work around the Pentium FDIV bug.
2065 int MSVCRT__adjust_fdiv
= 0;
2067 /***********************************************************************
2068 * _adj_fdiv_m16i (MSVCRT.@)
2071 * I _think_ this function is intended to work around the Pentium
2074 void __stdcall
_adj_fdiv_m16i( short arg
)
2076 TRACE("(): stub\n");
2079 /***********************************************************************
2080 * _adj_fdiv_m32 (MSVCRT.@)
2083 * I _think_ this function is intended to work around the Pentium
2086 void __stdcall
_adj_fdiv_m32( unsigned int arg
)
2088 TRACE("(): stub\n");
2091 /***********************************************************************
2092 * _adj_fdiv_m32i (MSVCRT.@)
2095 * I _think_ this function is intended to work around the Pentium
2098 void __stdcall
_adj_fdiv_m32i( int arg
)
2100 TRACE("(): stub\n");
2103 /***********************************************************************
2104 * _adj_fdiv_m64 (MSVCRT.@)
2107 * I _think_ this function is intended to work around the Pentium
2110 void __stdcall
_adj_fdiv_m64( unsigned __int64 arg
)
2112 TRACE("(): stub\n");
2115 /***********************************************************************
2116 * _adj_fdiv_r (MSVCRT.@)
2118 * This function is likely to have the wrong number of arguments.
2121 * I _think_ this function is intended to work around the Pentium
2124 void _adj_fdiv_r(void)
2126 TRACE("(): stub\n");
2129 /***********************************************************************
2130 * _adj_fdivr_m16i (MSVCRT.@)
2133 * I _think_ this function is intended to work around the Pentium
2136 void __stdcall
_adj_fdivr_m16i( short arg
)
2138 TRACE("(): stub\n");
2141 /***********************************************************************
2142 * _adj_fdivr_m32 (MSVCRT.@)
2145 * I _think_ this function is intended to work around the Pentium
2148 void __stdcall
_adj_fdivr_m32( unsigned int arg
)
2150 TRACE("(): stub\n");
2153 /***********************************************************************
2154 * _adj_fdivr_m32i (MSVCRT.@)
2157 * I _think_ this function is intended to work around the Pentium
2160 void __stdcall
_adj_fdivr_m32i( int arg
)
2162 TRACE("(): stub\n");
2165 /***********************************************************************
2166 * _adj_fdivr_m64 (MSVCRT.@)
2169 * I _think_ this function is intended to work around the Pentium
2172 void __stdcall
_adj_fdivr_m64( unsigned __int64 arg
)
2174 TRACE("(): stub\n");
2177 /***********************************************************************
2178 * _adj_fpatan (MSVCRT.@)
2180 * This function is likely to have the wrong number of arguments.
2183 * I _think_ this function is intended to work around the Pentium
2186 void _adj_fpatan(void)
2188 TRACE("(): stub\n");
2191 /***********************************************************************
2192 * _adj_fprem (MSVCRT.@)
2194 * This function is likely to have the wrong number of arguments.
2197 * I _think_ this function is intended to work around the Pentium
2200 void _adj_fprem(void)
2202 TRACE("(): stub\n");
2205 /***********************************************************************
2206 * _adj_fprem1 (MSVCRT.@)
2208 * This function is likely to have the wrong number of arguments.
2211 * I _think_ this function is intended to work around the Pentium
2214 void _adj_fprem1(void)
2216 TRACE("(): stub\n");
2219 /***********************************************************************
2220 * _adj_fptan (MSVCRT.@)
2222 * This function is likely to have the wrong number of arguments.
2225 * I _think_ this function is intended to work around the Pentium
2228 void _adj_fptan(void)
2230 TRACE("(): stub\n");
2233 /***********************************************************************
2234 * _safe_fdiv (MSVCRT.@)
2236 * This function is likely to have the wrong number of arguments.
2239 * I _think_ this function is intended to work around the Pentium
2242 void _safe_fdiv(void)
2244 TRACE("(): stub\n");
2247 /***********************************************************************
2248 * _safe_fdivr (MSVCRT.@)
2250 * This function is likely to have the wrong number of arguments.
2253 * I _think_ this function is intended to work around the Pentium
2256 void _safe_fdivr(void)
2258 TRACE("(): stub\n");
2261 /***********************************************************************
2262 * _safe_fprem (MSVCRT.@)
2264 * This function is likely to have the wrong number of arguments.
2267 * I _think_ this function is intended to work around the Pentium
2270 void _safe_fprem(void)
2272 TRACE("(): stub\n");
2275 /***********************************************************************
2276 * _safe_fprem1 (MSVCRT.@)
2279 * This function is likely to have the wrong number of arguments.
2282 * I _think_ this function is intended to work around the Pentium
2285 void _safe_fprem1(void)
2287 TRACE("(): stub\n");
2290 /***********************************************************************
2291 * __libm_sse2_acos (MSVCRT.@)
2293 void __cdecl
__libm_sse2_acos(void)
2296 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2298 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2301 /***********************************************************************
2302 * __libm_sse2_acosf (MSVCRT.@)
2304 void __cdecl
__libm_sse2_acosf(void)
2307 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2309 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2312 /***********************************************************************
2313 * __libm_sse2_asin (MSVCRT.@)
2315 void __cdecl
__libm_sse2_asin(void)
2318 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2320 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2323 /***********************************************************************
2324 * __libm_sse2_asinf (MSVCRT.@)
2326 void __cdecl
__libm_sse2_asinf(void)
2329 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2331 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2334 /***********************************************************************
2335 * __libm_sse2_atan (MSVCRT.@)
2337 void __cdecl
__libm_sse2_atan(void)
2340 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2342 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2345 /***********************************************************************
2346 * __libm_sse2_atan2 (MSVCRT.@)
2348 void __cdecl
__libm_sse2_atan2(void)
2351 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
2352 d1
= atan2( d1
, d2
);
2353 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
2356 /***********************************************************************
2357 * __libm_sse2_atanf (MSVCRT.@)
2359 void __cdecl
__libm_sse2_atanf(void)
2362 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2364 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2367 /***********************************************************************
2368 * __libm_sse2_cos (MSVCRT.@)
2370 void __cdecl
__libm_sse2_cos(void)
2373 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2375 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2378 /***********************************************************************
2379 * __libm_sse2_cosf (MSVCRT.@)
2381 void __cdecl
__libm_sse2_cosf(void)
2384 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2386 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2389 /***********************************************************************
2390 * __libm_sse2_exp (MSVCRT.@)
2392 void __cdecl
__libm_sse2_exp(void)
2395 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2397 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2400 /***********************************************************************
2401 * __libm_sse2_expf (MSVCRT.@)
2403 void __cdecl
__libm_sse2_expf(void)
2406 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2408 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2411 /***********************************************************************
2412 * __libm_sse2_log (MSVCRT.@)
2414 void __cdecl
__libm_sse2_log(void)
2417 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2419 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2422 /***********************************************************************
2423 * __libm_sse2_log10 (MSVCRT.@)
2425 void __cdecl
__libm_sse2_log10(void)
2428 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2430 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2433 /***********************************************************************
2434 * __libm_sse2_log10f (MSVCRT.@)
2436 void __cdecl
__libm_sse2_log10f(void)
2439 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2441 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2444 /***********************************************************************
2445 * __libm_sse2_logf (MSVCRT.@)
2447 void __cdecl
__libm_sse2_logf(void)
2450 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2452 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2455 /***********************************************************************
2456 * __libm_sse2_pow (MSVCRT.@)
2458 void __cdecl
__libm_sse2_pow(void)
2461 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
2463 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
2466 /***********************************************************************
2467 * __libm_sse2_powf (MSVCRT.@)
2469 void __cdecl
__libm_sse2_powf(void)
2472 __asm__
__volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1
), "=g" (f2
) );
2473 f1
= powf( f1
, f2
);
2474 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f1
) );
2477 /***********************************************************************
2478 * __libm_sse2_sin (MSVCRT.@)
2480 void __cdecl
__libm_sse2_sin(void)
2483 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2485 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2488 /***********************************************************************
2489 * __libm_sse2_sinf (MSVCRT.@)
2491 void __cdecl
__libm_sse2_sinf(void)
2494 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2496 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2499 /***********************************************************************
2500 * __libm_sse2_tan (MSVCRT.@)
2502 void __cdecl
__libm_sse2_tan(void)
2505 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2507 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2510 /***********************************************************************
2511 * __libm_sse2_tanf (MSVCRT.@)
2513 void __cdecl
__libm_sse2_tanf(void)
2516 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2518 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2521 /***********************************************************************
2522 * __libm_sse2_sqrt_precise (MSVCR110.@)
2524 void __cdecl
__libm_sse2_sqrt_precise(void)
2529 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2530 __control87_2(0, 0, NULL
, &cw
);
2534 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2538 if (!sqrt_validate(&d
, FALSE
))
2540 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2543 __asm__
__volatile__( "call " __ASM_NAME( "sse2_sqrt" ) );
2545 #endif /* __i386__ */
2549 /*********************************************************************
2550 * lrint (MSVCR120.@)
2552 __msvcrt_long CDECL
lrint(double x
)
2557 if ((d
< 0 && d
!= (double)(__msvcrt_long
)d
)
2558 || (d
>= 0 && d
!= (double)(__msvcrt_ulong
)d
)) {
2565 /*********************************************************************
2566 * lrintf (MSVCR120.@)
2568 __msvcrt_long CDECL
lrintf(float x
)
2573 if ((f
< 0 && f
!= (float)(__msvcrt_long
)f
)
2574 || (f
>= 0 && f
!= (float)(__msvcrt_ulong
)f
)) {
2581 /*********************************************************************
2582 * llrint (MSVCR120.@)
2584 __int64 CDECL
llrint(double x
)
2589 if ((d
< 0 && d
!= (double)(__int64
)d
)
2590 || (d
>= 0 && d
!= (double)(unsigned __int64
)d
)) {
2597 /*********************************************************************
2598 * llrintf (MSVCR120.@)
2600 __int64 CDECL
llrintf(float x
)
2605 if ((f
< 0 && f
!= (float)(__int64
)f
)
2606 || (f
>= 0 && f
!= (float)(unsigned __int64
)f
)) {
2613 /*********************************************************************
2614 * lround (MSVCR120.@)
2616 * Copied from musl: src/math/lround.c
2618 __msvcrt_long CDECL
lround(double x
)
2620 double d
= round(x
);
2621 if (d
!= (double)(__msvcrt_long
)d
) {
2628 /*********************************************************************
2629 * lroundf (MSVCR120.@)
2631 * Copied from musl: src/math/lroundf.c
2633 __msvcrt_long CDECL
lroundf(float x
)
2635 float f
= roundf(x
);
2636 if (f
!= (float)(__msvcrt_long
)f
) {
2643 /*********************************************************************
2644 * llround (MSVCR120.@)
2646 * Copied from musl: src/math/llround.c
2648 __int64 CDECL
llround(double x
)
2650 double d
= round(x
);
2651 if (d
!= (double)(__int64
)d
) {
2658 /*********************************************************************
2659 * llroundf (MSVCR120.@)
2661 * Copied from musl: src/math/llroundf.c
2663 __int64 CDECL
llroundf(float x
)
2665 float f
= roundf(x
);
2666 if (f
!= (float)(__int64
)f
) {
2673 /*********************************************************************
2674 * _dtest (MSVCR120.@)
2676 short CDECL
_dtest(double *x
)
2681 /*********************************************************************
2682 * _fdtest (MSVCR120.@)
2684 short CDECL
_fdtest(float *x
)
2686 return _fdclass(*x
);
2689 /*********************************************************************
2690 * _fdsign (MSVCR120.@)
2692 int CDECL
_fdsign(float x
)
2694 union { float f
; UINT32 i
; } u
= { x
};
2695 return (u
.i
>> 16) & 0x8000;
2698 /*********************************************************************
2699 * _dsign (MSVCR120.@)
2701 int CDECL
_dsign(double x
)
2703 union { double f
; UINT64 i
; } u
= { x
};
2704 return (u
.i
>> 48) & 0x8000;
2707 /*********************************************************************
2708 * _dpcomp (MSVCR120.@)
2710 int CDECL
_dpcomp(double x
, double y
)
2712 if(isnan(x
) || isnan(y
))
2715 if(x
== y
) return 2;
2716 return x
< y
? 1 : 4;
2719 /*********************************************************************
2720 * _fdpcomp (MSVCR120.@)
2722 int CDECL
_fdpcomp(float x
, float y
)
2724 return _dpcomp(x
, y
);
2727 /*********************************************************************
2728 * acosh (MSVCR120.@)
2730 double CDECL
MSVCRT_acosh(double x
)
2735 feraiseexcept(FE_INVALID
);
2741 /*********************************************************************
2742 * acoshf (MSVCR120.@)
2744 float CDECL
MSVCRT_acoshf(float x
)
2749 feraiseexcept(FE_INVALID
);
2755 /*********************************************************************
2756 * atanh (MSVCR120.@)
2758 double CDECL
MSVCRT_atanh(double x
)
2763 feraiseexcept(FE_INVALID
);
2769 /*********************************************************************
2770 * atanhf (MSVCR120.@)
2772 float CDECL
MSVCRT_atanhf(float x
)
2777 feraiseexcept(FE_INVALID
);
2783 #endif /* _MSVCR_VER>=120 */
2785 /*********************************************************************
2787 * scalbn (MSVCR120.@)
2788 * scalbln (MSVCR120.@)
2790 double CDECL
_scalb(double num
, __msvcrt_long power
)
2792 return ldexp(num
, power
);
2795 /*********************************************************************
2796 * _scalbf (MSVCRT.@)
2797 * scalbnf (MSVCR120.@)
2798 * scalblnf (MSVCR120.@)
2800 float CDECL
_scalbf(float num
, __msvcrt_long power
)
2802 return ldexp(num
, power
);
2805 #if _MSVCR_VER == 120 /* other versions call remainder() directly */
2807 /*********************************************************************
2808 * remainder (MSVCR120.@)
2810 double CDECL
MSVCRT_remainder(double x
, double y
)
2813 if (isnan(x
) || isnan(y
)) *_errno() = EDOM
;
2815 return remainder(x
, y
);
2818 /*********************************************************************
2819 * remainderf (MSVCR120.@)
2821 float CDECL
MSVCRT_remainderf(float x
, float y
)
2824 if (isnan(x
) || isnan(y
)) *_errno() = EDOM
;
2826 return remainderf(x
, y
);
2829 #endif /* _MSVCR_VER == 120 */
2833 /*********************************************************************
2834 * _except1 (MSVCR120.@)
2836 * - find meaning of ignored cw and operation bits
2839 double CDECL
_except1(DWORD fpe
, _FP_OPERATION_CODE op
, double arg
, double res
, DWORD cw
, void *unk
)
2841 ULONG_PTR exception_arg
;
2842 DWORD exception
= 0;
2843 unsigned int fpword
= 0;
2847 TRACE("(%lx %x %lf %lf %lx %p)\n", fpe
, op
, arg
, res
, cw
, unk
);
2850 cw
= ((cw
>> 7) & 0x3f) | ((cw
>> 3) & 0xc00);
2852 operation
= op
<< 5;
2853 exception_arg
= (ULONG_PTR
)&operation
;
2855 if (fpe
& 0x1) { /* overflow */
2856 if ((fpe
== 0x1 && (cw
& 0x8)) || (fpe
==0x11 && (cw
& 0x28))) {
2857 /* 32-bit version also sets SW_INEXACT here */
2858 raise
|= FE_OVERFLOW
;
2859 if (fpe
& 0x10) raise
|= FE_INEXACT
;
2860 res
= signbit(res
) ? -INFINITY
: INFINITY
;
2862 exception
= EXCEPTION_FLT_OVERFLOW
;
2864 } else if (fpe
& 0x2) { /* underflow */
2865 if ((fpe
== 0x2 && (cw
& 0x10)) || (fpe
==0x12 && (cw
& 0x30))) {
2866 raise
|= FE_UNDERFLOW
;
2867 if (fpe
& 0x10) raise
|= FE_INEXACT
;
2868 res
= signbit(res
) ? -0.0 : 0.0;
2870 exception
= EXCEPTION_FLT_UNDERFLOW
;
2872 } else if (fpe
& 0x4) { /* zerodivide */
2873 if ((fpe
== 0x4 && (cw
& 0x4)) || (fpe
==0x14 && (cw
& 0x24))) {
2874 raise
|= FE_DIVBYZERO
;
2875 if (fpe
& 0x10) raise
|= FE_INEXACT
;
2877 exception
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
2879 } else if (fpe
& 0x8) { /* invalid */
2880 if (fpe
== 0x8 && (cw
& 0x1)) {
2881 raise
|= FE_INVALID
;
2883 exception
= EXCEPTION_FLT_INVALID_OPERATION
;
2885 } else if (fpe
& 0x10) { /* inexact */
2886 if (fpe
== 0x10 && (cw
& 0x20)) {
2887 raise
|= FE_INEXACT
;
2889 exception
= EXCEPTION_FLT_INEXACT_RESULT
;
2895 feraiseexcept(raise
);
2897 RaiseException(exception
, 0, 1, &exception_arg
);
2899 if (cw
& 0x1) fpword
|= _EM_INVALID
;
2900 if (cw
& 0x2) fpword
|= _EM_DENORMAL
;
2901 if (cw
& 0x4) fpword
|= _EM_ZERODIVIDE
;
2902 if (cw
& 0x8) fpword
|= _EM_OVERFLOW
;
2903 if (cw
& 0x10) fpword
|= _EM_UNDERFLOW
;
2904 if (cw
& 0x20) fpword
|= _EM_INEXACT
;
2907 case 0xc00: fpword
|= _RC_UP
|_RC_DOWN
; break;
2908 case 0x800: fpword
|= _RC_UP
; break;
2909 case 0x400: fpword
|= _RC_DOWN
; break;
2913 case 0x0: fpword
|= _PC_24
; break;
2914 case 0x200: fpword
|= _PC_53
; break;
2915 case 0x300: fpword
|= _PC_64
; break;
2917 if (cw
& 0x1000) fpword
|= _IC_AFFINE
;
2918 _setfp(&fpword
, _MCW_EM
| _MCW_RC
| _MCW_PC
| _MCW_IC
, NULL
, 0);
2923 _Dcomplex
* CDECL
_Cbuild(_Dcomplex
*ret
, double r
, double i
)
2930 double CDECL
MSVCR120_creal(_Dcomplex z
)
2935 #endif /* _MSVCR_VER>=120 */