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 #include "wine/port.h"
24 #define __USE_ISOC9X 1
25 #define __USE_ISOC99 1
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
38 #define finitef(x) isfinite(x)
43 #define isnanf(x) isnan(x)
49 /* FIXME: Does not work with -NAN and -0. */
51 #define signbit(x) ((x) < 0)
54 #define _DOMAIN 1 /* domain error in argument */
55 #define _SING 2 /* singularity */
56 #define _OVERFLOW 3 /* range overflow */
57 #define _UNDERFLOW 4 /* range underflow */
59 typedef int (CDECL
*MSVCRT_matherr_func
)(struct MSVCRT__exception
*);
60 typedef double LDOUBLE
; /* long double is just a double */
62 static MSVCRT_matherr_func MSVCRT_default_matherr_func
= NULL
;
64 static BOOL sse2_supported
;
65 static BOOL sse2_enabled
;
67 void msvcrt_init_math(void)
69 sse2_supported
= sse2_enabled
= IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE
);
72 /*********************************************************************
75 int CDECL
MSVCRT__matherr(struct MSVCRT__exception
*e
)
80 TRACE("(%p = {%d, \"%s\", %g, %g, %g})\n", e
, e
->type
, e
->name
, e
->arg1
, e
->arg2
, e
->retval
);
84 if (MSVCRT_default_matherr_func
)
86 ret
= MSVCRT_default_matherr_func(e
);
93 *MSVCRT__errno() = MSVCRT_EDOM
;
97 *MSVCRT__errno() = MSVCRT_ERANGE
;
100 /* don't set errno */
103 ERR("Unhandled math error!\n");
109 /*********************************************************************
110 * __setusermatherr (MSVCRT.@)
112 void CDECL
MSVCRT___setusermatherr(MSVCRT_matherr_func func
)
114 MSVCRT_default_matherr_func
= func
;
115 TRACE("new matherr handler %p\n", func
);
118 static inline void math_error(int type
, const char *name
, double arg1
, double arg2
, double retval
)
120 struct MSVCRT__exception exception
= {type
, (char *)name
, arg1
, arg2
, retval
};
121 MSVCRT__matherr(&exception
);
124 /*********************************************************************
125 * _set_SSE2_enable (MSVCRT.@)
127 int CDECL
MSVCRT__set_SSE2_enable(int flag
)
129 sse2_enabled
= flag
&& sse2_supported
;
134 /*********************************************************************
135 * _set_FMA3_enable (MSVCR120.@)
137 int CDECL
MSVCRT__set_FMA3_enable(int flag
)
139 FIXME("(%x) stub\n", flag
);
144 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || _MSVCR_VER>=120
146 /*********************************************************************
147 * _chgsignf (MSVCRT.@)
149 float CDECL
MSVCRT__chgsignf( float num
)
151 /* FIXME: +-infinity,Nan not tested */
155 /*********************************************************************
156 * _copysignf (MSVCRT.@)
158 float CDECL
MSVCRT__copysignf( float num
, float sign
)
161 return signbit(num
) ? num
: -num
;
162 return signbit(num
) ? -num
: num
;
165 /*********************************************************************
166 * _nextafterf (MSVCRT.@)
168 float CDECL
MSVCRT__nextafterf( float num
, float next
)
170 if (!finitef(num
) || !finitef(next
)) *MSVCRT__errno() = MSVCRT_EDOM
;
171 return nextafterf( num
, next
);
175 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
177 /*********************************************************************
178 * _finitef (MSVCRT.@)
180 int CDECL
MSVCRT__finitef( float num
)
182 return finitef(num
) != 0; /* See comment for _isnan() */
185 /*********************************************************************
188 INT CDECL
MSVCRT__isnanf( float num
)
190 /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
191 * Do the same, as the result may be used in calculations
193 return isnanf(num
) != 0;
196 /*********************************************************************
199 float CDECL
MSVCRT__logbf( float num
)
201 float ret
= logbf(num
);
202 if (isnanf(num
)) math_error(_DOMAIN
, "_logbf", num
, 0, ret
);
203 else if (!num
) math_error(_SING
, "_logbf", num
, 0, ret
);
207 /*********************************************************************
208 * MSVCRT_acosf (MSVCRT.@)
210 float CDECL
MSVCRT_acosf( float x
)
212 /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
213 * asin() uses a similar construction. This is bad because as x gets nearer to
214 * 1 the error in the expression "1 - x^2" can get relatively large due to
215 * cancellation. The sqrt() makes things worse. A safer way to calculate
216 * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
217 float ret
= atan2f(sqrtf((1 - x
) * (1 + x
)), x
);
218 if (x
< -1.0 || x
> 1.0 || !finitef(x
)) math_error(_DOMAIN
, "acosf", x
, 0, ret
);
222 /*********************************************************************
223 * MSVCRT_asinf (MSVCRT.@)
225 float CDECL
MSVCRT_asinf( float x
)
227 float ret
= atan2f(x
, sqrtf((1 - x
) * (1 + x
)));
228 if (x
< -1.0 || x
> 1.0 || !finitef(x
)) math_error(_DOMAIN
, "asinf", x
, 0, ret
);
232 /*********************************************************************
233 * MSVCRT_atanf (MSVCRT.@)
235 float CDECL
MSVCRT_atanf( float x
)
237 float ret
= atanf(x
);
238 if (!finitef(x
)) math_error(_DOMAIN
, "atanf", x
, 0, ret
);
242 /*********************************************************************
243 * MSVCRT_atan2f (MSVCRT.@)
245 float CDECL
MSVCRT_atan2f( float x
, float y
)
247 float ret
= atan2f(x
, y
);
248 if (isnanf(x
)) math_error(_DOMAIN
, "atan2f", x
, y
, ret
);
252 /*********************************************************************
253 * MSVCRT_cosf (MSVCRT.@)
255 float CDECL
MSVCRT_cosf( float x
)
258 if (!finitef(x
)) math_error(_DOMAIN
, "cosf", x
, 0, ret
);
262 /*********************************************************************
263 * MSVCRT_coshf (MSVCRT.@)
265 float CDECL
MSVCRT_coshf( float x
)
267 float ret
= coshf(x
);
268 if (isnanf(x
)) math_error(_DOMAIN
, "coshf", x
, 0, ret
);
272 /*********************************************************************
273 * MSVCRT_expf (MSVCRT.@)
275 float CDECL
MSVCRT_expf( float x
)
278 if (isnanf(x
)) math_error(_DOMAIN
, "expf", x
, 0, ret
);
279 else if (finitef(x
) && !ret
) math_error(_UNDERFLOW
, "expf", x
, 0, ret
);
280 else if (finitef(x
) && !finitef(ret
)) math_error(_OVERFLOW
, "expf", x
, 0, ret
);
284 /*********************************************************************
285 * MSVCRT_fmodf (MSVCRT.@)
287 float CDECL
MSVCRT_fmodf( float x
, float y
)
289 float ret
= fmodf(x
, y
);
290 if (!finitef(x
) || !finitef(y
)) math_error(_DOMAIN
, "fmodf", x
, 0, ret
);
294 /*********************************************************************
295 * MSVCRT_logf (MSVCRT.@)
297 float CDECL
MSVCRT_logf( float x
)
300 if (x
< 0.0) math_error(_DOMAIN
, "logf", x
, 0, ret
);
301 else if (x
== 0.0) math_error(_SING
, "logf", x
, 0, ret
);
305 /*********************************************************************
306 * MSVCRT_log10f (MSVCRT.@)
308 float CDECL
MSVCRT_log10f( float x
)
310 float ret
= log10f(x
);
311 if (x
< 0.0) math_error(_DOMAIN
, "log10f", x
, 0, ret
);
312 else if (x
== 0.0) math_error(_SING
, "log10f", x
, 0, ret
);
316 /*********************************************************************
317 * MSVCRT_powf (MSVCRT.@)
319 float CDECL
MSVCRT_powf( float x
, float y
)
321 /* FIXME: If x < 0 and y is not integral, set EDOM */
323 if (!finitef(z
)) math_error(_DOMAIN
, "powf", x
, 0, z
);
327 /*********************************************************************
328 * MSVCRT_sinf (MSVCRT.@)
330 float CDECL
MSVCRT_sinf( float x
)
333 if (!finitef(x
)) math_error(_DOMAIN
, "sinf", x
, 0, ret
);
337 /*********************************************************************
338 * MSVCRT_sinhf (MSVCRT.@)
340 float CDECL
MSVCRT_sinhf( float x
)
342 float ret
= sinhf(x
);
343 if (isnanf(x
)) math_error(_DOMAIN
, "sinhf", x
, 0, ret
);
347 /*********************************************************************
348 * MSVCRT_sqrtf (MSVCRT.@)
350 float CDECL
MSVCRT_sqrtf( float x
)
352 float ret
= sqrtf(x
);
353 if (x
< 0.0) math_error(_DOMAIN
, "sqrtf", x
, 0, ret
);
357 /*********************************************************************
358 * MSVCRT_tanf (MSVCRT.@)
360 float CDECL
MSVCRT_tanf( float x
)
363 if (!finitef(x
)) math_error(_DOMAIN
, "tanf", x
, 0, ret
);
367 /*********************************************************************
368 * MSVCRT_tanhf (MSVCRT.@)
370 float CDECL
MSVCRT_tanhf( float x
)
372 float ret
= tanhf(x
);
373 if (!finitef(x
)) math_error(_DOMAIN
, "tanhf", x
, 0, ret
);
377 /*********************************************************************
380 float CDECL
MSVCRT_ceilf( float x
)
385 /*********************************************************************
388 float CDECL
MSVCRT_fabsf( float x
)
393 /*********************************************************************
396 float CDECL
MSVCRT_floorf( float x
)
401 /*********************************************************************
404 float CDECL
MSVCRT_frexpf( float x
, int *exp
)
406 return frexpf( x
, exp
);
409 /*********************************************************************
412 float CDECL
MSVCRT_modff( float x
, float *iptr
)
414 return modff( x
, iptr
);
419 /*********************************************************************
420 * MSVCRT_acos (MSVCRT.@)
422 double CDECL
MSVCRT_acos( double x
)
424 /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
425 * asin() uses a similar construction. This is bad because as x gets nearer to
426 * 1 the error in the expression "1 - x^2" can get relatively large due to
427 * cancellation. The sqrt() makes things worse. A safer way to calculate
428 * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
429 double ret
= atan2(sqrt((1 - x
) * (1 + x
)), x
);
430 if (x
< -1.0 || x
> 1.0 || !isfinite(x
)) math_error(_DOMAIN
, "acos", x
, 0, ret
);
434 /*********************************************************************
435 * MSVCRT_asin (MSVCRT.@)
437 double CDECL
MSVCRT_asin( double x
)
439 double ret
= atan2(x
, sqrt((1 - x
) * (1 + x
)));
440 if (x
< -1.0 || x
> 1.0 || !isfinite(x
)) math_error(_DOMAIN
, "asin", x
, 0, ret
);
444 /*********************************************************************
445 * MSVCRT_atan (MSVCRT.@)
447 double CDECL
MSVCRT_atan( double x
)
449 double ret
= atan(x
);
450 if (isnan(x
)) math_error(_DOMAIN
, "atan", x
, 0, ret
);
454 /*********************************************************************
455 * MSVCRT_atan2 (MSVCRT.@)
457 double CDECL
MSVCRT_atan2( double x
, double y
)
459 double ret
= atan2(x
, y
);
460 if (isnan(x
)) math_error(_DOMAIN
, "atan2", x
, y
, ret
);
464 /*********************************************************************
465 * MSVCRT_cos (MSVCRT.@)
467 double CDECL
MSVCRT_cos( double x
)
470 if (!isfinite(x
)) math_error(_DOMAIN
, "cos", x
, 0, ret
);
474 /*********************************************************************
475 * MSVCRT_cosh (MSVCRT.@)
477 double CDECL
MSVCRT_cosh( double x
)
479 double ret
= cosh(x
);
480 if (isnan(x
)) math_error(_DOMAIN
, "cosh", x
, 0, ret
);
484 /*********************************************************************
485 * MSVCRT_exp (MSVCRT.@)
487 double CDECL
MSVCRT_exp( double x
)
490 if (isnan(x
)) math_error(_DOMAIN
, "exp", x
, 0, ret
);
491 else if (isfinite(x
) && !ret
) math_error(_UNDERFLOW
, "exp", x
, 0, ret
);
492 else if (isfinite(x
) && !isfinite(ret
)) math_error(_OVERFLOW
, "exp", x
, 0, ret
);
496 /*********************************************************************
497 * MSVCRT_fmod (MSVCRT.@)
499 double CDECL
MSVCRT_fmod( double x
, double y
)
501 double ret
= fmod(x
, y
);
502 if (!isfinite(x
) || !isfinite(y
)) math_error(_DOMAIN
, "fmod", x
, y
, ret
);
506 /*********************************************************************
507 * MSVCRT_log (MSVCRT.@)
509 double CDECL
MSVCRT_log( double x
)
512 if (x
< 0.0) math_error(_DOMAIN
, "log", x
, 0, ret
);
513 else if (x
== 0.0) math_error(_SING
, "log", x
, 0, ret
);
517 /*********************************************************************
518 * MSVCRT_log10 (MSVCRT.@)
520 double CDECL
MSVCRT_log10( double x
)
522 double ret
= log10(x
);
523 if (x
< 0.0) math_error(_DOMAIN
, "log10", x
, 0, ret
);
524 else if (x
== 0.0) math_error(_SING
, "log10", x
, 0, ret
);
528 /*********************************************************************
529 * MSVCRT_pow (MSVCRT.@)
531 double CDECL
MSVCRT_pow( double x
, double y
)
533 /* FIXME: If x < 0 and y is not integral, set EDOM */
535 if (!isfinite(z
)) math_error(_DOMAIN
, "pow", x
, y
, z
);
539 /*********************************************************************
540 * MSVCRT_sin (MSVCRT.@)
542 double CDECL
MSVCRT_sin( double x
)
545 if (!isfinite(x
)) math_error(_DOMAIN
, "sin", x
, 0, ret
);
549 /*********************************************************************
550 * MSVCRT_sinh (MSVCRT.@)
552 double CDECL
MSVCRT_sinh( double x
)
554 double ret
= sinh(x
);
555 if (isnan(x
)) math_error(_DOMAIN
, "sinh", x
, 0, ret
);
559 /*********************************************************************
560 * MSVCRT_sqrt (MSVCRT.@)
562 double CDECL
MSVCRT_sqrt( double x
)
564 double ret
= sqrt(x
);
565 if (x
< 0.0) math_error(_DOMAIN
, "sqrt", x
, 0, ret
);
569 /*********************************************************************
570 * MSVCRT_tan (MSVCRT.@)
572 double CDECL
MSVCRT_tan( double x
)
575 if (!isfinite(x
)) math_error(_DOMAIN
, "tan", x
, 0, ret
);
579 /*********************************************************************
580 * MSVCRT_tanh (MSVCRT.@)
582 double CDECL
MSVCRT_tanh( double x
)
584 double ret
= tanh(x
);
585 if (isnan(x
)) math_error(_DOMAIN
, "tanh", x
, 0, ret
);
590 #if defined(__GNUC__) && defined(__i386__)
592 #define FPU_DOUBLE(var) double var; \
593 __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
594 #define FPU_DOUBLES(var1,var2) double var1,var2; \
595 __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
596 __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
598 /*********************************************************************
601 double CDECL
_CIacos(void)
604 return MSVCRT_acos(x
);
607 /*********************************************************************
610 double CDECL
_CIasin(void)
613 return MSVCRT_asin(x
);
616 /*********************************************************************
619 double CDECL
_CIatan(void)
622 return MSVCRT_atan(x
);
625 /*********************************************************************
626 * _CIatan2 (MSVCRT.@)
628 double CDECL
_CIatan2(void)
631 return MSVCRT_atan2(x
,y
);
634 /*********************************************************************
637 double CDECL
_CIcos(void)
640 return MSVCRT_cos(x
);
643 /*********************************************************************
646 double CDECL
_CIcosh(void)
649 return MSVCRT_cosh(x
);
652 /*********************************************************************
655 double CDECL
_CIexp(void)
658 return MSVCRT_exp(x
);
661 /*********************************************************************
664 double CDECL
_CIfmod(void)
667 return MSVCRT_fmod(x
,y
);
670 /*********************************************************************
673 double CDECL
_CIlog(void)
676 return MSVCRT_log(x
);
679 /*********************************************************************
680 * _CIlog10 (MSVCRT.@)
682 double CDECL
_CIlog10(void)
685 return MSVCRT_log10(x
);
688 /*********************************************************************
691 double CDECL
_CIpow(void)
694 return MSVCRT_pow(x
,y
);
697 /*********************************************************************
700 double CDECL
_CIsin(void)
703 return MSVCRT_sin(x
);
706 /*********************************************************************
709 double CDECL
_CIsinh(void)
712 return MSVCRT_sinh(x
);
715 /*********************************************************************
718 double CDECL
_CIsqrt(void)
721 return MSVCRT_sqrt(x
);
724 /*********************************************************************
727 double CDECL
_CItan(void)
730 return MSVCRT_tan(x
);
733 /*********************************************************************
736 double CDECL
_CItanh(void)
739 return MSVCRT_tanh(x
);
742 /*********************************************************************
745 LONGLONG CDECL
MSVCRT__ftol(void)
751 #endif /* defined(__GNUC__) && defined(__i386__) */
753 /*********************************************************************
754 * _fpclass (MSVCRT.@)
756 int CDECL
MSVCRT__fpclass(double num
)
758 #if defined(HAVE_FPCLASS) || defined(fpclass)
759 switch (fpclass( num
))
761 case FP_SNAN
: return MSVCRT__FPCLASS_SNAN
;
762 case FP_QNAN
: return MSVCRT__FPCLASS_QNAN
;
763 case FP_NINF
: return MSVCRT__FPCLASS_NINF
;
764 case FP_PINF
: return MSVCRT__FPCLASS_PINF
;
765 case FP_NDENORM
: return MSVCRT__FPCLASS_ND
;
766 case FP_PDENORM
: return MSVCRT__FPCLASS_PD
;
767 case FP_NZERO
: return MSVCRT__FPCLASS_NZ
;
768 case FP_PZERO
: return MSVCRT__FPCLASS_PZ
;
769 case FP_NNORM
: return MSVCRT__FPCLASS_NN
;
770 case FP_PNORM
: return MSVCRT__FPCLASS_PN
;
771 default: return MSVCRT__FPCLASS_PN
;
773 #elif defined (fpclassify)
774 switch (fpclassify( num
))
776 case FP_NAN
: return MSVCRT__FPCLASS_QNAN
;
777 case FP_INFINITE
: return signbit(num
) ? MSVCRT__FPCLASS_NINF
: MSVCRT__FPCLASS_PINF
;
778 case FP_SUBNORMAL
: return signbit(num
) ?MSVCRT__FPCLASS_ND
: MSVCRT__FPCLASS_PD
;
779 case FP_ZERO
: return signbit(num
) ? MSVCRT__FPCLASS_NZ
: MSVCRT__FPCLASS_PZ
;
781 return signbit(num
) ? MSVCRT__FPCLASS_NN
: MSVCRT__FPCLASS_PN
;
784 return MSVCRT__FPCLASS_QNAN
;
785 return num
== 0.0 ? MSVCRT__FPCLASS_PZ
: (num
< 0 ? MSVCRT__FPCLASS_NN
: MSVCRT__FPCLASS_PN
);
789 /*********************************************************************
792 unsigned int CDECL
_rotl(unsigned int num
, int shift
)
795 return (num
<< shift
) | (num
>> (32-shift
));
798 /*********************************************************************
801 MSVCRT_ulong CDECL
MSVCRT__lrotl(MSVCRT_ulong num
, int shift
)
804 return (num
<< shift
) | (num
>> (32-shift
));
807 /*********************************************************************
810 MSVCRT_ulong CDECL
MSVCRT__lrotr(MSVCRT_ulong num
, int shift
)
813 return (num
>> shift
) | (num
<< (32-shift
));
816 /*********************************************************************
819 unsigned int CDECL
_rotr(unsigned int num
, int shift
)
822 return (num
>> shift
) | (num
<< (32-shift
));
825 /*********************************************************************
828 unsigned __int64 CDECL
_rotl64(unsigned __int64 num
, int shift
)
831 return (num
<< shift
) | (num
>> (64-shift
));
834 /*********************************************************************
837 unsigned __int64 CDECL
_rotr64(unsigned __int64 num
, int shift
)
840 return (num
>> shift
) | (num
<< (64-shift
));
843 /*********************************************************************
846 int CDECL
MSVCRT_abs( int n
)
848 return n
>= 0 ? n
: -n
;
851 /*********************************************************************
854 MSVCRT_long CDECL
MSVCRT_labs( MSVCRT_long n
)
856 return n
>= 0 ? n
: -n
;
859 /*********************************************************************
862 MSVCRT_longlong CDECL
MSVCRT_llabs( MSVCRT_longlong n
)
864 return n
>= 0 ? n
: -n
;
867 /*********************************************************************
870 __int64 CDECL
_abs64( __int64 n
)
872 return n
>= 0 ? n
: -n
;
875 /*********************************************************************
878 double CDECL
MSVCRT__logb(double num
)
880 double ret
= logb(num
);
881 if (isnan(num
)) math_error(_DOMAIN
, "_logb", num
, 0, ret
);
882 else if (!num
) math_error(_SING
, "_logb", num
, 0, ret
);
886 /*********************************************************************
889 double CDECL
_hypot(double x
, double y
)
891 /* FIXME: errno handling */
892 return hypot( x
, y
);
895 /*********************************************************************
898 float CDECL
MSVCRT__hypotf(float x
, float y
)
900 /* FIXME: errno handling */
901 return hypotf( x
, y
);
904 /*********************************************************************
907 double CDECL
MSVCRT_ceil( double x
)
912 /*********************************************************************
915 double CDECL
MSVCRT_floor( double x
)
920 /*********************************************************************
923 double CDECL
MSVCRT_fabs( double x
)
928 /*********************************************************************
931 double CDECL
MSVCRT_frexp( double x
, int *exp
)
933 return frexp( x
, exp
);
936 /*********************************************************************
939 double CDECL
MSVCRT_modf( double x
, double *iptr
)
941 return modf( x
, iptr
);
944 /**********************************************************************
945 * _statusfp2 (MSVCRT.@)
947 * Not exported by native msvcrt, added in msvcr80.
949 #if defined(__i386__) || defined(__x86_64__)
950 void CDECL
_statusfp2( unsigned int *x86_sw
, unsigned int *sse2_sw
)
954 unsigned long fpword
;
958 __asm__
__volatile__( "fstsw %0" : "=m" (fpword
) );
960 if (fpword
& 0x1) flags
|= MSVCRT__SW_INVALID
;
961 if (fpword
& 0x2) flags
|= MSVCRT__SW_DENORMAL
;
962 if (fpword
& 0x4) flags
|= MSVCRT__SW_ZERODIVIDE
;
963 if (fpword
& 0x8) flags
|= MSVCRT__SW_OVERFLOW
;
964 if (fpword
& 0x10) flags
|= MSVCRT__SW_UNDERFLOW
;
965 if (fpword
& 0x20) flags
|= MSVCRT__SW_INEXACT
;
969 if (!sse2_sw
) return;
973 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
975 if (fpword
& 0x1) flags
|= MSVCRT__SW_INVALID
;
976 if (fpword
& 0x2) flags
|= MSVCRT__SW_DENORMAL
;
977 if (fpword
& 0x4) flags
|= MSVCRT__SW_ZERODIVIDE
;
978 if (fpword
& 0x8) flags
|= MSVCRT__SW_OVERFLOW
;
979 if (fpword
& 0x10) flags
|= MSVCRT__SW_UNDERFLOW
;
980 if (fpword
& 0x20) flags
|= MSVCRT__SW_INEXACT
;
985 FIXME( "not implemented\n" );
990 /**********************************************************************
991 * _statusfp (MSVCRT.@)
993 unsigned int CDECL
_statusfp(void)
995 #if defined(__i386__) || defined(__x86_64__)
996 unsigned int x86_sw
, sse2_sw
;
998 _statusfp2( &x86_sw
, &sse2_sw
);
999 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1000 return x86_sw
| sse2_sw
;
1002 FIXME( "not implemented\n" );
1007 /*********************************************************************
1008 * _clearfp (MSVCRT.@)
1010 unsigned int CDECL
_clearfp(void)
1012 unsigned int flags
= 0;
1013 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1014 unsigned long fpword
;
1016 __asm__
__volatile__( "fnstsw %0; fnclex" : "=m" (fpword
) );
1017 if (fpword
& 0x1) flags
|= MSVCRT__SW_INVALID
;
1018 if (fpword
& 0x2) flags
|= MSVCRT__SW_DENORMAL
;
1019 if (fpword
& 0x4) flags
|= MSVCRT__SW_ZERODIVIDE
;
1020 if (fpword
& 0x8) flags
|= MSVCRT__SW_OVERFLOW
;
1021 if (fpword
& 0x10) flags
|= MSVCRT__SW_UNDERFLOW
;
1022 if (fpword
& 0x20) flags
|= MSVCRT__SW_INEXACT
;
1026 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1027 if (fpword
& 0x1) flags
|= MSVCRT__SW_INVALID
;
1028 if (fpword
& 0x2) flags
|= MSVCRT__SW_DENORMAL
;
1029 if (fpword
& 0x4) flags
|= MSVCRT__SW_ZERODIVIDE
;
1030 if (fpword
& 0x8) flags
|= MSVCRT__SW_OVERFLOW
;
1031 if (fpword
& 0x10) flags
|= MSVCRT__SW_UNDERFLOW
;
1032 if (fpword
& 0x20) flags
|= MSVCRT__SW_INEXACT
;
1034 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
1037 FIXME( "not implemented\n" );
1042 /*********************************************************************
1043 * __fpecode (MSVCRT.@)
1045 int * CDECL
__fpecode(void)
1047 return &msvcrt_get_thread_data()->fpecode
;
1050 /*********************************************************************
1053 double CDECL
MSVCRT_ldexp(double num
, MSVCRT_long exp
)
1055 double z
= ldexp(num
,exp
);
1057 if (isfinite(num
) && !isfinite(z
))
1058 math_error(_OVERFLOW
, "ldexp", num
, exp
, z
);
1059 else if (isfinite(num
) && !z
)
1060 math_error(_UNDERFLOW
, "ldexp", num
, exp
, z
);
1061 else if (z
== 0 && signbit(z
))
1062 z
= 0.0; /* Convert -0 -> +0 */
1066 /*********************************************************************
1069 double CDECL
MSVCRT__cabs(struct MSVCRT__complex num
)
1071 return sqrt(num
.x
* num
.x
+ num
.y
* num
.y
);
1074 /*********************************************************************
1075 * _chgsign (MSVCRT.@)
1077 double CDECL
MSVCRT__chgsign(double num
)
1079 /* FIXME: +-infinity,Nan not tested */
1083 /*********************************************************************
1084 * __control87_2 (MSVCRT.@)
1086 * Not exported by native msvcrt, added in msvcr80.
1088 #if defined(__i386__) || defined(__x86_64__)
1089 int CDECL
__control87_2( unsigned int newval
, unsigned int mask
,
1090 unsigned int *x86_cw
, unsigned int *sse2_cw
)
1093 unsigned long fpword
;
1098 __asm__
__volatile__( "fstcw %0" : "=m" (fpword
) );
1100 /* Convert into mask constants */
1102 if (fpword
& 0x1) flags
|= MSVCRT__EM_INVALID
;
1103 if (fpword
& 0x2) flags
|= MSVCRT__EM_DENORMAL
;
1104 if (fpword
& 0x4) flags
|= MSVCRT__EM_ZERODIVIDE
;
1105 if (fpword
& 0x8) flags
|= MSVCRT__EM_OVERFLOW
;
1106 if (fpword
& 0x10) flags
|= MSVCRT__EM_UNDERFLOW
;
1107 if (fpword
& 0x20) flags
|= MSVCRT__EM_INEXACT
;
1108 switch (fpword
& 0xc00)
1110 case 0xc00: flags
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
1111 case 0x800: flags
|= MSVCRT__RC_UP
; break;
1112 case 0x400: flags
|= MSVCRT__RC_DOWN
; break;
1114 switch (fpword
& 0x300)
1116 case 0x0: flags
|= MSVCRT__PC_24
; break;
1117 case 0x200: flags
|= MSVCRT__PC_53
; break;
1118 case 0x300: flags
|= MSVCRT__PC_64
; break;
1120 if (fpword
& 0x1000) flags
|= MSVCRT__IC_AFFINE
;
1122 TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags
, newval
, mask
);
1125 flags
= (flags
& ~mask
) | (newval
& mask
);
1127 /* Convert (masked) value back to fp word */
1129 if (flags
& MSVCRT__EM_INVALID
) fpword
|= 0x1;
1130 if (flags
& MSVCRT__EM_DENORMAL
) fpword
|= 0x2;
1131 if (flags
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x4;
1132 if (flags
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x8;
1133 if (flags
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x10;
1134 if (flags
& MSVCRT__EM_INEXACT
) fpword
|= 0x20;
1135 switch (flags
& MSVCRT__MCW_RC
)
1137 case MSVCRT__RC_UP
|MSVCRT__RC_DOWN
: fpword
|= 0xc00; break;
1138 case MSVCRT__RC_UP
: fpword
|= 0x800; break;
1139 case MSVCRT__RC_DOWN
: fpword
|= 0x400; break;
1141 switch (flags
& MSVCRT__MCW_PC
)
1143 case MSVCRT__PC_64
: fpword
|= 0x300; break;
1144 case MSVCRT__PC_53
: fpword
|= 0x200; break;
1145 case MSVCRT__PC_24
: fpword
|= 0x0; break;
1147 if (flags
& MSVCRT__IC_AFFINE
) fpword
|= 0x1000;
1149 __asm__
__volatile__( "fldcw %0" : : "m" (fpword
) );
1154 if (!sse2_cw
) return 1;
1158 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1160 /* Convert into mask constants */
1162 if (fpword
& 0x80) flags
|= MSVCRT__EM_INVALID
;
1163 if (fpword
& 0x100) flags
|= MSVCRT__EM_DENORMAL
;
1164 if (fpword
& 0x200) flags
|= MSVCRT__EM_ZERODIVIDE
;
1165 if (fpword
& 0x400) flags
|= MSVCRT__EM_OVERFLOW
;
1166 if (fpword
& 0x800) flags
|= MSVCRT__EM_UNDERFLOW
;
1167 if (fpword
& 0x1000) flags
|= MSVCRT__EM_INEXACT
;
1168 switch (fpword
& 0x6000)
1170 case 0x6000: flags
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
1171 case 0x4000: flags
|= MSVCRT__RC_UP
; break;
1172 case 0x2000: flags
|= MSVCRT__RC_DOWN
; break;
1174 switch (fpword
& 0x8040)
1176 case 0x0040: flags
|= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
; break;
1177 case 0x8000: flags
|= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
; break;
1178 case 0x8040: flags
|= MSVCRT__DN_FLUSH
; break;
1181 TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags
, newval
, mask
);
1184 flags
= (flags
& ~mask
) | (newval
& mask
);
1186 /* Convert (masked) value back to fp word */
1188 if (flags
& MSVCRT__EM_INVALID
) fpword
|= 0x80;
1189 if (flags
& MSVCRT__EM_DENORMAL
) fpword
|= 0x100;
1190 if (flags
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x200;
1191 if (flags
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x400;
1192 if (flags
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x800;
1193 if (flags
& MSVCRT__EM_INEXACT
) fpword
|= 0x1000;
1194 switch (flags
& MSVCRT__MCW_RC
)
1196 case MSVCRT__RC_UP
|MSVCRT__RC_DOWN
: fpword
|= 0x6000; break;
1197 case MSVCRT__RC_UP
: fpword
|= 0x4000; break;
1198 case MSVCRT__RC_DOWN
: fpword
|= 0x2000; break;
1200 switch (flags
& MSVCRT__MCW_DN
)
1202 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS
: fpword
|= 0x0040; break;
1203 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS
: fpword
|= 0x8000; break;
1204 case MSVCRT__DN_FLUSH
: fpword
|= 0x8040; break;
1206 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
1214 FIXME( "not implemented\n" );
1220 /*********************************************************************
1221 * _control87 (MSVCRT.@)
1223 unsigned int CDECL
_control87(unsigned int newval
, unsigned int mask
)
1225 #if defined(__i386__) || defined(__x86_64__)
1226 unsigned int x86_cw
, sse2_cw
;
1228 __control87_2( newval
, mask
, &x86_cw
, &sse2_cw
);
1230 if ((x86_cw
^ sse2_cw
) & (MSVCRT__MCW_EM
| MSVCRT__MCW_RC
)) x86_cw
|= MSVCRT__EM_AMBIGUOUS
;
1233 FIXME( "not implemented\n" );
1238 /*********************************************************************
1239 * _controlfp (MSVCRT.@)
1241 unsigned int CDECL
_controlfp(unsigned int newval
, unsigned int mask
)
1243 return _control87( newval
, mask
& ~MSVCRT__EM_DENORMAL
);
1246 /*********************************************************************
1247 * _set_controlfp (MSVCRT.@)
1249 void CDECL
_set_controlfp( unsigned int newval
, unsigned int mask
)
1251 _controlfp( newval
, mask
);
1254 /*********************************************************************
1255 * _controlfp_s (MSVCRT.@)
1257 int CDECL
_controlfp_s(unsigned int *cur
, unsigned int newval
, unsigned int mask
)
1259 static const unsigned int all_flags
= (MSVCRT__MCW_EM
| MSVCRT__MCW_IC
| MSVCRT__MCW_RC
|
1260 MSVCRT__MCW_PC
| MSVCRT__MCW_DN
);
1263 if (!MSVCRT_CHECK_PMT( !(newval
& mask
& ~all_flags
) ))
1265 if (cur
) *cur
= _controlfp( 0, 0 ); /* retrieve it anyway */
1266 return MSVCRT_EINVAL
;
1268 val
= _controlfp( newval
, mask
);
1269 if (cur
) *cur
= val
;
1273 /*********************************************************************
1274 * fegetenv (MSVCR120.@)
1276 int CDECL
MSVCRT_fegetenv(MSVCRT_fenv_t
*env
)
1278 env
->control
= _controlfp(0, 0) & (MSVCRT__EM_INEXACT
| MSVCRT__EM_UNDERFLOW
|
1279 MSVCRT__EM_OVERFLOW
| MSVCRT__EM_ZERODIVIDE
| MSVCRT__EM_INVALID
);
1280 env
->status
= _statusfp();
1284 /*********************************************************************
1285 * __fpe_flt_rounds (UCRTBASE.@)
1287 int CDECL
__fpe_flt_rounds(void)
1289 unsigned int fpc
= _controlfp(0, 0) & MSVCRT__RC_CHOP
;
1294 case MSVCRT__RC_CHOP
: return 0;
1295 case MSVCRT__RC_NEAR
: return 1;
1297 case MSVCRT__RC_UP
: return 3;
1300 case MSVCRT__RC_UP
: return 2;
1306 /*********************************************************************
1307 * fegetround (MSVCR120.@)
1309 int CDECL
MSVCRT_fegetround(void)
1311 return _controlfp(0, 0) & MSVCRT__RC_CHOP
;
1314 /*********************************************************************
1315 * fesetround (MSVCR120.@)
1317 int CDECL
MSVCRT_fesetround(int round_mode
)
1319 if (round_mode
& (~MSVCRT__RC_CHOP
))
1321 _controlfp(round_mode
, MSVCRT__RC_CHOP
);
1325 /*********************************************************************
1326 * _copysign (MSVCRT.@)
1328 double CDECL
MSVCRT__copysign(double num
, double sign
)
1331 return signbit(num
) ? num
: -num
;
1332 return signbit(num
) ? -num
: num
;
1335 /*********************************************************************
1336 * _finite (MSVCRT.@)
1338 int CDECL
MSVCRT__finite(double num
)
1340 return isfinite(num
) != 0; /* See comment for _isnan() */
1343 /*********************************************************************
1344 * _fpreset (MSVCRT.@)
1346 void CDECL
_fpreset(void)
1348 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1349 const unsigned int x86_cw
= 0x27f;
1350 __asm__
__volatile__( "fninit; fldcw %0" : : "m" (x86_cw
) );
1353 const unsigned long sse2_cw
= 0x1f80;
1354 __asm__
__volatile__( "ldmxcsr %0" : : "m" (sse2_cw
) );
1357 FIXME( "not implemented\n" );
1361 /*********************************************************************
1362 * fesetenv (MSVCR120.@)
1364 int CDECL
MSVCRT_fesetenv(const MSVCRT_fenv_t
*env
)
1366 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1374 DWORD instruction_pointer
;
1382 TRACE( "(%p)\n", env
);
1384 if (!env
->control
&& !env
->status
) {
1389 __asm__
__volatile__( "fnstenv %0" : "=m" (fenv
) );
1391 fenv
.control_word
&= ~0x3d;
1392 if (env
->control
& MSVCRT__EM_INVALID
) fenv
.control_word
|= 0x1;
1393 if (env
->control
& MSVCRT__EM_ZERODIVIDE
) fenv
.control_word
|= 0x4;
1394 if (env
->control
& MSVCRT__EM_OVERFLOW
) fenv
.control_word
|= 0x8;
1395 if (env
->control
& MSVCRT__EM_UNDERFLOW
) fenv
.control_word
|= 0x10;
1396 if (env
->control
& MSVCRT__EM_INEXACT
) fenv
.control_word
|= 0x20;
1398 fenv
.status_word
&= ~0x3d;
1399 if (env
->status
& MSVCRT__SW_INVALID
) fenv
.status_word
|= 0x1;
1400 if (env
->status
& MSVCRT__SW_ZERODIVIDE
) fenv
.status_word
|= 0x4;
1401 if (env
->status
& MSVCRT__SW_OVERFLOW
) fenv
.status_word
|= 0x8;
1402 if (env
->status
& MSVCRT__SW_UNDERFLOW
) fenv
.status_word
|= 0x10;
1403 if (env
->status
& MSVCRT__SW_INEXACT
) fenv
.status_word
|= 0x20;
1405 __asm__
__volatile__( "fldenv %0" : : "m" (fenv
) : "st", "st(1)",
1406 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
1412 __asm__
__volatile__( "stmxcsr %0" : "=m" (fpword
) );
1414 if (env
->control
& MSVCRT__EM_INVALID
) fpword
|= 0x80;
1415 if (env
->control
& MSVCRT__EM_ZERODIVIDE
) fpword
|= 0x200;
1416 if (env
->control
& MSVCRT__EM_OVERFLOW
) fpword
|= 0x400;
1417 if (env
->control
& MSVCRT__EM_UNDERFLOW
) fpword
|= 0x800;
1418 if (env
->control
& MSVCRT__EM_INEXACT
) fpword
|= 0x1000;
1419 __asm__
__volatile__( "ldmxcsr %0" : : "m" (fpword
) );
1424 FIXME( "not implemented\n" );
1429 /*********************************************************************
1432 INT CDECL
MSVCRT__isnan(double num
)
1434 /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
1435 * Do the same, as the result may be used in calculations
1437 return isnan(num
) != 0;
1440 /*********************************************************************
1443 double CDECL
MSVCRT__j0(double num
)
1445 /* FIXME: errno handling */
1449 /*********************************************************************
1452 double CDECL
MSVCRT__j1(double num
)
1454 /* FIXME: errno handling */
1458 /*********************************************************************
1461 double CDECL
MSVCRT__jn(int n
, double num
)
1463 /* FIXME: errno handling */
1467 /*********************************************************************
1470 double CDECL
MSVCRT__y0(double num
)
1473 if (!isfinite(num
)) *MSVCRT__errno() = MSVCRT_EDOM
;
1475 if (MSVCRT__fpclass(retval
) == MSVCRT__FPCLASS_NINF
)
1477 *MSVCRT__errno() = MSVCRT_EDOM
;
1483 /*********************************************************************
1486 double CDECL
MSVCRT__y1(double num
)
1489 if (!isfinite(num
)) *MSVCRT__errno() = MSVCRT_EDOM
;
1491 if (MSVCRT__fpclass(retval
) == MSVCRT__FPCLASS_NINF
)
1493 *MSVCRT__errno() = MSVCRT_EDOM
;
1499 /*********************************************************************
1502 double CDECL
MSVCRT__yn(int order
, double num
)
1505 if (!isfinite(num
)) *MSVCRT__errno() = MSVCRT_EDOM
;
1506 retval
= yn(order
,num
);
1507 if (MSVCRT__fpclass(retval
) == MSVCRT__FPCLASS_NINF
)
1509 *MSVCRT__errno() = MSVCRT_EDOM
;
1515 /*********************************************************************
1516 * _nearbyint (MSVCRT.@)
1518 double CDECL
MSVCRT_nearbyint(double num
)
1520 #ifdef HAVE_NEARBYINT
1521 return nearbyint(num
);
1523 return num
>= 0 ? floor(num
+ 0.5) : ceil(num
- 0.5);
1527 /*********************************************************************
1528 * _nearbyintf (MSVCRT.@)
1530 float CDECL
MSVCRT_nearbyintf(float num
)
1532 #ifdef HAVE_NEARBYINTF
1533 return nearbyintf(num
);
1535 return MSVCRT_nearbyint(num
);
1539 /*********************************************************************
1540 * _nextafter (MSVCRT.@)
1542 double CDECL
MSVCRT__nextafter(double num
, double next
)
1545 if (!isfinite(num
) || !isfinite(next
)) *MSVCRT__errno() = MSVCRT_EDOM
;
1546 retval
= nextafter(num
,next
);
1550 /*********************************************************************
1553 char * CDECL
MSVCRT__ecvt( double number
, int ndigits
, int *decpt
, int *sign
)
1556 thread_data_t
*data
= msvcrt_get_thread_data();
1557 /* FIXME: check better for overflow (native supports over 300 chars) */
1558 ndigits
= min( ndigits
, 80 - 7); /* 7 : space for dec point, 1 for "e",
1559 * 4 for exponent and one for
1560 * terminating '\0' */
1561 if (!data
->efcvt_buffer
)
1562 data
->efcvt_buffer
= MSVCRT_malloc( 80 ); /* ought to be enough */
1569 /* handle cases with zero ndigits or less */
1571 if( prec
< 1) prec
= 2;
1572 len
= snprintf(data
->efcvt_buffer
, 80, "%.*le", prec
- 1, number
);
1573 /* take the decimal "point away */
1575 memmove( data
->efcvt_buffer
+ 1, data
->efcvt_buffer
+ 2, len
- 1 );
1576 /* take the exponential "e" out */
1577 data
->efcvt_buffer
[ prec
] = '\0';
1578 /* read the exponent */
1579 sscanf( data
->efcvt_buffer
+ prec
+ 1, "%d", decpt
);
1581 /* adjust for some border cases */
1582 if( data
->efcvt_buffer
[0] == '0')/* value is zero */
1584 /* handle cases with zero ndigits or less */
1586 if( data
->efcvt_buffer
[ 0] >= '5')
1588 data
->efcvt_buffer
[ 0] = '\0';
1590 TRACE("out=\"%s\"\n",data
->efcvt_buffer
);
1591 return data
->efcvt_buffer
;
1594 /*********************************************************************
1595 * _ecvt_s (MSVCRT.@)
1597 int CDECL
MSVCRT__ecvt_s( char *buffer
, MSVCRT_size_t length
, double number
, int ndigits
, int *decpt
, int *sign
)
1601 const char infret
[] = "1#INF";
1603 if (!MSVCRT_CHECK_PMT(buffer
!= NULL
)) return MSVCRT_EINVAL
;
1604 if (!MSVCRT_CHECK_PMT(decpt
!= NULL
)) return MSVCRT_EINVAL
;
1605 if (!MSVCRT_CHECK_PMT(sign
!= NULL
)) return MSVCRT_EINVAL
;
1606 if (!MSVCRT_CHECK_PMT_ERR( length
> 2, MSVCRT_ERANGE
)) return MSVCRT_ERANGE
;
1607 if (!MSVCRT_CHECK_PMT_ERR(ndigits
< (int)length
- 1, MSVCRT_ERANGE
)) return MSVCRT_ERANGE
;
1609 /* special case - inf */
1610 if(number
== HUGE_VAL
|| number
== -HUGE_VAL
)
1612 memset(buffer
, '0', ndigits
);
1613 memcpy(buffer
, infret
, min(ndigits
, sizeof(infret
) - 1 ) );
1614 buffer
[ndigits
] = '\0';
1616 if(number
== -HUGE_VAL
)
1622 /* handle cases with zero ndigits or less */
1624 if( prec
< 1) prec
= 2;
1625 result
= MSVCRT_malloc(prec
+ 7);
1632 len
= snprintf(result
, prec
+ 7, "%.*le", prec
- 1, number
);
1633 /* take the decimal "point away */
1635 memmove( result
+ 1, result
+ 2, len
- 1 );
1636 /* take the exponential "e" out */
1637 result
[ prec
] = '\0';
1638 /* read the exponent */
1639 sscanf( result
+ prec
+ 1, "%d", decpt
);
1641 /* adjust for some border cases */
1642 if( result
[0] == '0')/* value is zero */
1644 /* handle cases with zero ndigits or less */
1646 if( result
[ 0] >= '5')
1650 memcpy( buffer
, result
, max(ndigits
+ 1, 1) );
1651 MSVCRT_free( result
);
1655 /***********************************************************************
1658 char * CDECL
MSVCRT__fcvt( double number
, int ndigits
, int *decpt
, int *sign
)
1660 thread_data_t
*data
= msvcrt_get_thread_data();
1661 int stop
, dec1
, dec2
;
1662 char *ptr1
, *ptr2
, *first
;
1663 char buf
[80]; /* ought to be enough */
1665 if (!data
->efcvt_buffer
)
1666 data
->efcvt_buffer
= MSVCRT_malloc( 80 ); /* ought to be enough */
1674 stop
= snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
1676 ptr2
= data
->efcvt_buffer
;
1681 /* For numbers below the requested resolution, work out where
1682 the decimal point will be rather than finding it in the string */
1683 if (number
< 1.0 && number
> 0.0) {
1684 dec2
= log10(number
+ 1e-10);
1685 if (-dec2
<= ndigits
) dec2
= 0;
1688 /* If requested digits is zero or less, we will need to truncate
1689 * the returned string */
1694 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
1695 while (*ptr1
!= '\0' && *ptr1
!= '.') {
1696 if (!first
) first
= ptr2
;
1697 if ((ptr1
- buf
) < stop
) {
1708 while (*ptr1
== '0') { /* Process leading zeroes */
1713 while (*ptr1
!= '\0') {
1714 if (!first
) first
= ptr2
;
1721 /* We never found a non-zero digit, then our number is either
1722 * smaller than the requested precision, or 0.0 */
1727 first
= data
->efcvt_buffer
;
1732 *decpt
= dec2
? dec2
: dec1
;
1736 /***********************************************************************
1737 * _fcvt_s (MSVCRT.@)
1739 int CDECL
MSVCRT__fcvt_s(char* outbuffer
, MSVCRT_size_t size
, double number
, int ndigits
, int *decpt
, int *sign
)
1741 int stop
, dec1
, dec2
;
1742 char *ptr1
, *ptr2
, *first
;
1743 char buf
[80]; /* ought to be enough */
1745 if (!outbuffer
|| !decpt
|| !sign
|| size
== 0)
1747 *MSVCRT__errno() = MSVCRT_EINVAL
;
1748 return MSVCRT_EINVAL
;
1757 stop
= snprintf(buf
, 80, "%.*f", ndigits
< 0 ? 0 : ndigits
, number
);
1764 /* For numbers below the requested resolution, work out where
1765 the decimal point will be rather than finding it in the string */
1766 if (number
< 1.0 && number
> 0.0) {
1767 dec2
= log10(number
+ 1e-10);
1768 if (-dec2
<= ndigits
) dec2
= 0;
1771 /* If requested digits is zero or less, we will need to truncate
1772 * the returned string */
1777 while (*ptr1
== '0') ptr1
++; /* Skip leading zeroes */
1778 while (*ptr1
!= '\0' && *ptr1
!= '.') {
1779 if (!first
) first
= ptr2
;
1780 if ((ptr1
- buf
) < stop
) {
1794 while (*ptr1
== '0') { /* Process leading zeroes */
1795 if (number
== 0.0 && size
> 1) {
1803 while (*ptr1
!= '\0') {
1804 if (!first
) first
= ptr2
;
1814 /* We never found a non-zero digit, then our number is either
1815 * smaller than the requested precision, or 0.0 */
1816 if (!first
&& (number
<= 0.0))
1819 *decpt
= dec2
? dec2
: dec1
;
1823 /***********************************************************************
1826 char * CDECL
MSVCRT__gcvt( double number
, int ndigit
, char *buff
)
1829 *MSVCRT__errno() = MSVCRT_EINVAL
;
1834 *MSVCRT__errno() = MSVCRT_ERANGE
;
1838 MSVCRT_sprintf(buff
, "%.*g", ndigit
, number
);
1842 /***********************************************************************
1843 * _gcvt_s (MSVCRT.@)
1845 int CDECL
MSVCRT__gcvt_s(char *buff
, MSVCRT_size_t size
, double number
, int digits
)
1850 *MSVCRT__errno() = MSVCRT_EINVAL
;
1851 return MSVCRT_EINVAL
;
1854 if( digits
<0 || digits
>=size
) {
1858 *MSVCRT__errno() = MSVCRT_ERANGE
;
1859 return MSVCRT_ERANGE
;
1862 len
= MSVCRT__scprintf("%.*g", digits
, number
);
1865 *MSVCRT__errno() = MSVCRT_ERANGE
;
1866 return MSVCRT_ERANGE
;
1869 MSVCRT_sprintf(buff
, "%.*g", digits
, number
);
1873 #include <stdlib.h> /* div_t, ldiv_t */
1875 /*********************************************************************
1878 * [i386] Windows binary compatible - returns the struct in eax/edx.
1881 unsigned __int64 CDECL
MSVCRT_div(int num
, int denom
)
1883 div_t dt
= div(num
,denom
);
1884 return ((unsigned __int64
)dt
.rem
<< 32) | (unsigned int)dt
.quot
;
1887 /*********************************************************************
1890 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1892 MSVCRT_div_t CDECL
MSVCRT_div(int num
, int denom
)
1894 div_t dt
= div(num
,denom
);
1902 #endif /* ifdef __i386__ */
1905 /*********************************************************************
1908 * [i386] Windows binary compatible - returns the struct in eax/edx.
1911 unsigned __int64 CDECL
MSVCRT_ldiv(MSVCRT_long num
, MSVCRT_long denom
)
1913 ldiv_t ldt
= ldiv(num
,denom
);
1914 return ((unsigned __int64
)ldt
.rem
<< 32) | (MSVCRT_ulong
)ldt
.quot
;
1917 /*********************************************************************
1920 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1922 MSVCRT_ldiv_t CDECL
MSVCRT_ldiv(MSVCRT_long num
, MSVCRT_long denom
)
1924 ldiv_t result
= ldiv(num
,denom
);
1927 ret
.quot
= result
.quot
;
1928 ret
.rem
= result
.rem
;
1932 #endif /* ifdef __i386__ */
1934 /*********************************************************************
1937 MSVCRT_lldiv_t CDECL
MSVCRT_lldiv(MSVCRT_longlong num
, MSVCRT_longlong denom
)
1941 ret
.quot
= num
/ denom
;
1942 ret
.rem
= num
% denom
;
1949 /*********************************************************************
1950 * _adjust_fdiv (MSVCRT.@)
1951 * Used by the MSVC compiler to work around the Pentium FDIV bug.
1953 int MSVCRT__adjust_fdiv
= 0;
1955 /***********************************************************************
1956 * _adj_fdiv_m16i (MSVCRT.@)
1959 * I _think_ this function is intended to work around the Pentium
1962 void __stdcall
_adj_fdiv_m16i( short arg
)
1964 TRACE("(): stub\n");
1967 /***********************************************************************
1968 * _adj_fdiv_m32 (MSVCRT.@)
1971 * I _think_ this function is intended to work around the Pentium
1974 void __stdcall
_adj_fdiv_m32( unsigned int arg
)
1976 TRACE("(): stub\n");
1979 /***********************************************************************
1980 * _adj_fdiv_m32i (MSVCRT.@)
1983 * I _think_ this function is intended to work around the Pentium
1986 void __stdcall
_adj_fdiv_m32i( int arg
)
1988 TRACE("(): stub\n");
1991 /***********************************************************************
1992 * _adj_fdiv_m64 (MSVCRT.@)
1995 * I _think_ this function is intended to work around the Pentium
1998 void __stdcall
_adj_fdiv_m64( unsigned __int64 arg
)
2000 TRACE("(): stub\n");
2003 /***********************************************************************
2004 * _adj_fdiv_r (MSVCRT.@)
2006 * This function is likely to have the wrong number of arguments.
2009 * I _think_ this function is intended to work around the Pentium
2012 void _adj_fdiv_r(void)
2014 TRACE("(): stub\n");
2017 /***********************************************************************
2018 * _adj_fdivr_m16i (MSVCRT.@)
2021 * I _think_ this function is intended to work around the Pentium
2024 void __stdcall
_adj_fdivr_m16i( short arg
)
2026 TRACE("(): stub\n");
2029 /***********************************************************************
2030 * _adj_fdivr_m32 (MSVCRT.@)
2033 * I _think_ this function is intended to work around the Pentium
2036 void __stdcall
_adj_fdivr_m32( unsigned int arg
)
2038 TRACE("(): stub\n");
2041 /***********************************************************************
2042 * _adj_fdivr_m32i (MSVCRT.@)
2045 * I _think_ this function is intended to work around the Pentium
2048 void __stdcall
_adj_fdivr_m32i( int arg
)
2050 TRACE("(): stub\n");
2053 /***********************************************************************
2054 * _adj_fdivr_m64 (MSVCRT.@)
2057 * I _think_ this function is intended to work around the Pentium
2060 void __stdcall
_adj_fdivr_m64( unsigned __int64 arg
)
2062 TRACE("(): stub\n");
2065 /***********************************************************************
2066 * _adj_fpatan (MSVCRT.@)
2068 * This function is likely to have the wrong number of arguments.
2071 * I _think_ this function is intended to work around the Pentium
2074 void _adj_fpatan(void)
2076 TRACE("(): stub\n");
2079 /***********************************************************************
2080 * _adj_fprem (MSVCRT.@)
2082 * This function is likely to have the wrong number of arguments.
2085 * I _think_ this function is intended to work around the Pentium
2088 void _adj_fprem(void)
2090 TRACE("(): stub\n");
2093 /***********************************************************************
2094 * _adj_fprem1 (MSVCRT.@)
2096 * This function is likely to have the wrong number of arguments.
2099 * I _think_ this function is intended to work around the Pentium
2102 void _adj_fprem1(void)
2104 TRACE("(): stub\n");
2107 /***********************************************************************
2108 * _adj_fptan (MSVCRT.@)
2110 * This function is likely to have the wrong number of arguments.
2113 * I _think_ this function is intended to work around the Pentium
2116 void _adj_fptan(void)
2118 TRACE("(): stub\n");
2121 /***********************************************************************
2122 * _safe_fdiv (MSVCRT.@)
2124 * This function is likely to have the wrong number of arguments.
2127 * I _think_ this function is intended to work around the Pentium
2130 void _safe_fdiv(void)
2132 TRACE("(): stub\n");
2135 /***********************************************************************
2136 * _safe_fdivr (MSVCRT.@)
2138 * This function is likely to have the wrong number of arguments.
2141 * I _think_ this function is intended to work around the Pentium
2144 void _safe_fdivr(void)
2146 TRACE("(): stub\n");
2149 /***********************************************************************
2150 * _safe_fprem (MSVCRT.@)
2152 * This function is likely to have the wrong number of arguments.
2155 * I _think_ this function is intended to work around the Pentium
2158 void _safe_fprem(void)
2160 TRACE("(): stub\n");
2163 /***********************************************************************
2164 * _safe_fprem1 (MSVCRT.@)
2167 * This function is likely to have the wrong number of arguments.
2170 * I _think_ this function is intended to work around the Pentium
2173 void _safe_fprem1(void)
2175 TRACE("(): stub\n");
2178 /***********************************************************************
2179 * __libm_sse2_acos (MSVCRT.@)
2181 void __cdecl
MSVCRT___libm_sse2_acos(void)
2184 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2186 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2189 /***********************************************************************
2190 * __libm_sse2_acosf (MSVCRT.@)
2192 void __cdecl
MSVCRT___libm_sse2_acosf(void)
2195 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2197 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2200 /***********************************************************************
2201 * __libm_sse2_asin (MSVCRT.@)
2203 void __cdecl
MSVCRT___libm_sse2_asin(void)
2206 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2208 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2211 /***********************************************************************
2212 * __libm_sse2_asinf (MSVCRT.@)
2214 void __cdecl
MSVCRT___libm_sse2_asinf(void)
2217 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2219 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2222 /***********************************************************************
2223 * __libm_sse2_atan (MSVCRT.@)
2225 void __cdecl
MSVCRT___libm_sse2_atan(void)
2228 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2230 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2233 /***********************************************************************
2234 * __libm_sse2_atan2 (MSVCRT.@)
2236 void __cdecl
MSVCRT___libm_sse2_atan2(void)
2239 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
2240 d1
= atan2( d1
, d2
);
2241 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
2244 /***********************************************************************
2245 * __libm_sse2_atanf (MSVCRT.@)
2247 void __cdecl
MSVCRT___libm_sse2_atanf(void)
2250 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2252 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2255 /***********************************************************************
2256 * __libm_sse2_cos (MSVCRT.@)
2258 void __cdecl
MSVCRT___libm_sse2_cos(void)
2261 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2263 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2266 /***********************************************************************
2267 * __libm_sse2_cosf (MSVCRT.@)
2269 void __cdecl
MSVCRT___libm_sse2_cosf(void)
2272 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2274 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2277 /***********************************************************************
2278 * __libm_sse2_exp (MSVCRT.@)
2280 void __cdecl
MSVCRT___libm_sse2_exp(void)
2283 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2285 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2288 /***********************************************************************
2289 * __libm_sse2_expf (MSVCRT.@)
2291 void __cdecl
MSVCRT___libm_sse2_expf(void)
2294 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2296 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2299 /***********************************************************************
2300 * __libm_sse2_log (MSVCRT.@)
2302 void __cdecl
MSVCRT___libm_sse2_log(void)
2305 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2307 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2310 /***********************************************************************
2311 * __libm_sse2_log10 (MSVCRT.@)
2313 void __cdecl
MSVCRT___libm_sse2_log10(void)
2316 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2318 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2321 /***********************************************************************
2322 * __libm_sse2_log10f (MSVCRT.@)
2324 void __cdecl
MSVCRT___libm_sse2_log10f(void)
2327 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2329 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2332 /***********************************************************************
2333 * __libm_sse2_logf (MSVCRT.@)
2335 void __cdecl
MSVCRT___libm_sse2_logf(void)
2338 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2340 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2343 /***********************************************************************
2344 * __libm_sse2_pow (MSVCRT.@)
2346 void __cdecl
MSVCRT___libm_sse2_pow(void)
2349 __asm__
__volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1
), "=m" (d2
) );
2351 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d1
) );
2354 /***********************************************************************
2355 * __libm_sse2_powf (MSVCRT.@)
2357 void __cdecl
MSVCRT___libm_sse2_powf(void)
2360 __asm__
__volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1
), "=g" (f2
) );
2361 f1
= powf( f1
, f2
);
2362 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f1
) );
2365 /***********************************************************************
2366 * __libm_sse2_sin (MSVCRT.@)
2368 void __cdecl
MSVCRT___libm_sse2_sin(void)
2371 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2373 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2376 /***********************************************************************
2377 * __libm_sse2_sinf (MSVCRT.@)
2379 void __cdecl
MSVCRT___libm_sse2_sinf(void)
2382 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2384 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2387 /***********************************************************************
2388 * __libm_sse2_tan (MSVCRT.@)
2390 void __cdecl
MSVCRT___libm_sse2_tan(void)
2393 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2395 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2398 /***********************************************************************
2399 * __libm_sse2_tanf (MSVCRT.@)
2401 void __cdecl
MSVCRT___libm_sse2_tanf(void)
2404 __asm__
__volatile__( "movd %%xmm0,%0" : "=g" (f
) );
2406 __asm__
__volatile__( "movd %0,%%xmm0" : : "g" (f
) );
2409 /***********************************************************************
2410 * __libm_sse2_sqrt_precise (MSVCR110.@)
2412 void __cdecl
MSVCRT___libm_sse2_sqrt_precise(void)
2415 __asm__
__volatile__( "movq %%xmm0,%0" : "=m" (d
) );
2417 __asm__
__volatile__( "movq %0,%%xmm0" : : "m" (d
) );
2420 #endif /* __i386__ */
2422 /*********************************************************************
2425 double CDECL
MSVCR120_cbrt(double x
)
2430 return x
< 0 ? -pow(-x
, 1.0 / 3.0) : pow(x
, 1.0 / 3.0);
2434 /*********************************************************************
2435 * cbrtf (MSVCR120.@)
2437 float CDECL
MSVCR120_cbrtf(float x
)
2442 return MSVCR120_cbrt(x
);
2446 /*********************************************************************
2447 * cbrtl (MSVCR120.@)
2449 LDOUBLE CDECL
MSVCR120_cbrtl(LDOUBLE x
)
2451 return MSVCR120_cbrt(x
);
2454 /*********************************************************************
2457 double CDECL
MSVCR120_exp2(double x
)
2460 double ret
= exp2(x
);
2462 double ret
= pow(2, x
);
2464 if (isfinite(x
) && !isfinite(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
2468 /*********************************************************************
2469 * exp2f (MSVCR120.@)
2471 float CDECL
MSVCR120_exp2f(float x
)
2474 float ret
= exp2f(x
);
2475 if (finitef(x
) && !finitef(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
2478 return MSVCR120_exp2(x
);
2482 /*********************************************************************
2483 * exp2l (MSVCR120.@)
2485 LDOUBLE CDECL
MSVCR120_exp2l(LDOUBLE x
)
2487 return MSVCR120_exp2(x
);
2490 /*********************************************************************
2491 * expm1 (MSVCR120.@)
2493 double CDECL
MSVCR120_expm1(double x
)
2496 double ret
= expm1(x
);
2498 double ret
= exp(x
) - 1;
2500 if (isfinite(x
) && !isfinite(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
2504 /*********************************************************************
2505 * expm1f (MSVCR120.@)
2507 float CDECL
MSVCR120_expm1f(float x
)
2510 float ret
= expm1f(x
);
2512 float ret
= exp(x
) - 1;
2514 if (finitef(x
) && !finitef(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
2518 /*********************************************************************
2519 * expm1l (MSVCR120.@)
2521 LDOUBLE CDECL
MSVCR120_expm1l(LDOUBLE x
)
2523 return MSVCR120_expm1(x
);
2526 /*********************************************************************
2527 * log1p (MSVCR120.@)
2529 double CDECL
MSVCR120_log1p(double x
)
2531 if (x
< -1) *MSVCRT__errno() = MSVCRT_EDOM
;
2532 else if (x
== -1) *MSVCRT__errno() = MSVCRT_ERANGE
;
2540 /*********************************************************************
2541 * log1pf (MSVCR120.@)
2543 float CDECL
MSVCR120_log1pf(float x
)
2545 if (x
< -1) *MSVCRT__errno() = MSVCRT_EDOM
;
2546 else if (x
== -1) *MSVCRT__errno() = MSVCRT_ERANGE
;
2554 /*********************************************************************
2555 * log1pl (MSVCR120.@)
2557 LDOUBLE CDECL
MSVCR120_log1pl(LDOUBLE x
)
2559 return MSVCR120_log1p(x
);
2562 /*********************************************************************
2565 double CDECL
MSVCR120_log2(double x
)
2567 if (x
< 0) *MSVCRT__errno() = MSVCRT_EDOM
;
2568 else if (x
== 0) *MSVCRT__errno() = MSVCRT_ERANGE
;
2572 return log(x
) / log(2);
2576 /*********************************************************************
2577 * log2f (MSVCR120.@)
2579 float CDECL
MSVCR120_log2f(float x
)
2582 if (x
< 0) *MSVCRT__errno() = MSVCRT_EDOM
;
2583 else if (x
== 0) *MSVCRT__errno() = MSVCRT_ERANGE
;
2586 return MSVCR120_log2(x
);
2590 /*********************************************************************
2591 * log2l (MSVCR120.@)
2593 LDOUBLE CDECL
MSVCR120_log2l(LDOUBLE x
)
2595 return MSVCR120_log2(x
);
2598 /*********************************************************************
2601 double CDECL
MSVCR120_rint(double x
)
2606 return x
>= 0 ? floor(x
+ 0.5) : ceil(x
- 0.5);
2610 /*********************************************************************
2611 * rintf (MSVCR120.@)
2613 float CDECL
MSVCR120_rintf(float x
)
2618 return MSVCR120_rint(x
);
2622 /*********************************************************************
2623 * rintl (MSVCR120.@)
2625 LDOUBLE CDECL
MSVCR120_rintl(LDOUBLE x
)
2627 return MSVCR120_rint(x
);
2630 /*********************************************************************
2631 * lrint (MSVCR120.@)
2633 MSVCRT_long CDECL
MSVCR120_lrint(double x
)
2638 return MSVCR120_rint(x
);
2642 /*********************************************************************
2643 * lrintf (MSVCR120.@)
2645 MSVCRT_long CDECL
MSVCR120_lrintf(float x
)
2650 return MSVCR120_lrint(x
);
2654 /*********************************************************************
2655 * lrintl (MSVCR120.@)
2657 MSVCRT_long CDECL
MSVCR120_lrintl(LDOUBLE x
)
2659 return MSVCR120_lrint(x
);
2662 /*********************************************************************
2663 * llrint (MSVCR120.@)
2665 MSVCRT_longlong CDECL
MSVCR120_llrint(double x
)
2670 return MSVCR120_rint(x
);
2674 /*********************************************************************
2675 * llrintf (MSVCR120.@)
2677 MSVCRT_longlong CDECL
MSVCR120_llrintf(float x
)
2682 return MSVCR120_llrint(x
);
2686 /*********************************************************************
2687 * rintl (MSVCR120.@)
2689 MSVCRT_longlong CDECL
MSVCR120_llrintl(LDOUBLE x
)
2691 return MSVCR120_llrint(x
);
2694 /*********************************************************************
2695 * round (MSVCR120.@)
2697 double CDECL
MSVCR120_round(double x
)
2702 return MSVCR120_rint(x
);
2706 /*********************************************************************
2707 * roundf (MSVCR120.@)
2709 float CDECL
MSVCR120_roundf(float x
)
2714 return MSVCR120_round(x
);
2718 /*********************************************************************
2719 * roundl (MSVCR120.@)
2721 LDOUBLE CDECL
MSVCR120_roundl(LDOUBLE x
)
2723 return MSVCR120_round(x
);
2726 /*********************************************************************
2727 * lround (MSVCR120.@)
2729 MSVCRT_long CDECL
MSVCR120_lround(double x
)
2734 return MSVCR120_round(x
);
2738 /*********************************************************************
2739 * lroundf (MSVCR120.@)
2741 MSVCRT_long CDECL
MSVCR120_lroundf(float x
)
2746 return MSVCR120_lround(x
);
2750 /*********************************************************************
2751 * lroundl (MSVCR120.@)
2753 MSVCRT_long CDECL
MSVCR120_lroundl(LDOUBLE x
)
2755 return MSVCR120_lround(x
);
2758 /*********************************************************************
2759 * llround (MSVCR120.@)
2761 MSVCRT_longlong CDECL
MSVCR120_llround(double x
)
2766 return MSVCR120_round(x
);
2770 /*********************************************************************
2771 * llroundf (MSVCR120.@)
2773 MSVCRT_longlong CDECL
MSVCR120_llroundf(float x
)
2775 #ifdef HAVE_LLROUNDF
2778 return MSVCR120_llround(x
);
2782 /*********************************************************************
2783 * roundl (MSVCR120.@)
2785 MSVCRT_longlong CDECL
MSVCR120_llroundl(LDOUBLE x
)
2787 return MSVCR120_llround(x
);
2790 /*********************************************************************
2791 * trunc (MSVCR120.@)
2793 double CDECL
MSVCR120_trunc(double x
)
2798 return (x
> 0) ? floor(x
) : ceil(x
);
2802 /*********************************************************************
2803 * truncf (MSVCR120.@)
2805 float CDECL
MSVCR120_truncf(float x
)
2810 return MSVCR120_trunc(x
);
2814 /*********************************************************************
2815 * truncl (MSVCR120.@)
2817 LDOUBLE CDECL
MSVCR120_truncl(LDOUBLE x
)
2819 return MSVCR120_trunc(x
);
2822 /*********************************************************************
2823 * _dclass (MSVCR120.@)
2825 short CDECL
MSVCR120__dclass(double x
)
2827 switch (MSVCRT__fpclass(x
)) {
2828 case MSVCRT__FPCLASS_QNAN
:
2829 case MSVCRT__FPCLASS_SNAN
:
2830 return MSVCRT_FP_NAN
;
2831 case MSVCRT__FPCLASS_NINF
:
2832 case MSVCRT__FPCLASS_PINF
:
2833 return MSVCRT_FP_INFINITE
;
2834 case MSVCRT__FPCLASS_ND
:
2835 case MSVCRT__FPCLASS_PD
:
2836 return MSVCRT_FP_SUBNORMAL
;
2837 case MSVCRT__FPCLASS_NN
:
2838 case MSVCRT__FPCLASS_PN
:
2840 return MSVCRT_FP_NORMAL
;
2841 case MSVCRT__FPCLASS_NZ
:
2842 case MSVCRT__FPCLASS_PZ
:
2843 return MSVCRT_FP_ZERO
;
2847 /*********************************************************************
2848 * _fdclass (MSVCR120.@)
2850 short CDECL
MSVCR120__fdclass(float x
)
2852 return MSVCR120__dclass(x
);
2855 /*********************************************************************
2856 * _ldclass (MSVCR120.@)
2858 short CDECL
MSVCR120__ldclass(LDOUBLE x
)
2860 return MSVCR120__dclass(x
);
2863 /*********************************************************************
2864 * _dtest (MSVCR120.@)
2866 short CDECL
MSVCR120__dtest(double *x
)
2868 return MSVCR120__dclass(*x
);
2871 /*********************************************************************
2872 * _fdtest (MSVCR120.@)
2874 short CDECL
MSVCR120__fdtest(float *x
)
2876 return MSVCR120__dclass(*x
);
2879 /*********************************************************************
2880 * _ldtest (MSVCR120.@)
2882 short CDECL
MSVCR120__ldtest(LDOUBLE
*x
)
2884 return MSVCR120__dclass(*x
);
2887 /*********************************************************************
2890 double CDECL
MSVCR120_erf(double x
)
2895 /* Abramowitz and Stegun approximation, maximum error: 1.5*10^-7 */
2897 int sign
= signbit(x
);
2900 t
= 1 / (1 + 0.3275911 * x
);
2901 y
= ((((1.061405429*t
- 1.453152027)*t
+ 1.421413741)*t
- 0.284496736)*t
+ 0.254829592)*t
;
2902 y
= 1.0 - y
*exp(-x
*x
);
2903 return sign
? -y
: y
;
2907 /*********************************************************************
2910 float CDECL
MSVCR120_erff(float x
)
2915 return MSVCR120_erf(x
);
2919 /*********************************************************************
2922 LDOUBLE CDECL
MSVCR120_erfl(LDOUBLE x
)
2924 return MSVCR120_erf(x
);
2927 /*********************************************************************
2930 double CDECL
MSVCR120_erfc(double x
)
2935 return 1 - MSVCR120_erf(x
);
2939 /*********************************************************************
2940 * erfcf (MSVCR120.@)
2942 float CDECL
MSVCR120_erfcf(float x
)
2947 return MSVCR120_erfc(x
);
2951 /*********************************************************************
2952 * erfcl (MSVCR120.@)
2954 LDOUBLE CDECL
MSVCR120_erfcl(LDOUBLE x
)
2956 return MSVCR120_erfc(x
);
2959 /*********************************************************************
2960 * fmaxf (MSVCR120.@)
2962 float CDECL
MSVCR120_fmaxf(float x
, float y
)
2969 return signbit(x
) ? y
: x
;
2973 /*********************************************************************
2976 double CDECL
MSVCR120_fmax(double x
, double y
)
2983 return signbit(x
) ? y
: x
;
2987 /*********************************************************************
2988 * _fdsign (MSVCR120.@)
2990 int CDECL
MSVCR120__fdsign(float x
)
2992 return signbit(x
) ? 0x8000 : 0;
2995 /*********************************************************************
2996 * _dsign (MSVCR120.@)
2998 int CDECL
MSVCR120__dsign(double x
)
3000 return signbit(x
) ? 0x8000 : 0;
3004 /*********************************************************************
3005 * _dpcomp (MSVCR120.@)
3007 int CDECL
MSVCR120__dpcomp(double x
, double y
)
3009 if(isnan(x
) || isnan(y
))
3012 if(x
== y
) return 2;
3013 return x
< y
? 1 : 4;
3016 /*********************************************************************
3017 * _fdpcomp (MSVCR120.@)
3019 int CDECL
MSVCR120__fdpcomp(float x
, float y
)
3021 return MSVCR120__dpcomp(x
, y
);
3024 /*********************************************************************
3025 * fminf (MSVCR120.@)
3027 float CDECL
MSVCR120_fminf(float x
, float y
)
3034 return signbit(x
) ? x
: y
;
3038 /*********************************************************************
3041 double CDECL
MSVCR120_fmin(double x
, double y
)
3048 return signbit(x
) ? x
: y
;
3052 /*********************************************************************
3053 * asinh (MSVCR120.@)
3055 double CDECL
MSVCR120_asinh(double x
)
3060 if (!isfinite(x
*x
+1)) return log(2) + log(x
);
3061 return log(x
+ sqrt(x
*x
+1));
3065 /*********************************************************************
3066 * asinhf (MSVCR120.@)
3068 float CDECL
MSVCR120_asinhf(float x
)
3073 return MSVCR120_asinh(x
);
3077 /*********************************************************************
3078 * asinhl (MSVCR120.@)
3080 LDOUBLE CDECL
MSVCR120_asinhl(LDOUBLE x
)
3082 return MSVCR120_asinh(x
);
3085 /*********************************************************************
3086 * acosh (MSVCR120.@)
3088 double CDECL
MSVCR120_acosh(double x
)
3090 if (x
< 1) *MSVCRT__errno() = MSVCRT_EDOM
;
3098 MSVCRT_fegetenv(&env
);
3099 env
.status
|= MSVCRT__SW_INVALID
;
3100 MSVCRT_fesetenv(&env
);
3103 if (!isfinite(x
*x
)) return log(2) + log(x
);
3104 return log(x
+ sqrt(x
*x
-1));
3108 /*********************************************************************
3109 * acoshf (MSVCR120.@)
3111 float CDECL
MSVCR120_acoshf(float x
)
3114 if (x
< 1) *MSVCRT__errno() = MSVCRT_EDOM
;
3118 return MSVCR120_acosh(x
);
3122 /*********************************************************************
3123 * acoshl (MSVCR120.@)
3125 LDOUBLE CDECL
MSVCR120_acoshl(LDOUBLE x
)
3127 return MSVCR120_acosh(x
);
3130 /*********************************************************************
3131 * atanh (MSVCR120.@)
3133 double CDECL
MSVCR120_atanh(double x
)
3137 if (x
> 1 || x
< -1) {
3140 *MSVCRT__errno() = MSVCRT_EDOM
;
3142 /* on Linux atanh returns -NAN in this case */
3143 MSVCRT_fegetenv(&env
);
3144 env
.status
|= MSVCRT__SW_INVALID
;
3145 MSVCRT_fesetenv(&env
);
3152 if (-1e-6 < x
&& x
< 1e-6) ret
= x
+ x
*x
*x
/3;
3153 else ret
= (log(1+x
) - log(1-x
)) / 2;
3156 if (!isfinite(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
3160 /*********************************************************************
3161 * atanhf (MSVCR120.@)
3163 float CDECL
MSVCR120_atanhf(float x
)
3168 if (x
> 1 || x
< -1) {
3171 *MSVCRT__errno() = MSVCRT_EDOM
;
3173 MSVCRT_fegetenv(&env
);
3174 env
.status
|= MSVCRT__SW_INVALID
;
3175 MSVCRT_fesetenv(&env
);
3181 if (!finitef(ret
)) *MSVCRT__errno() = MSVCRT_ERANGE
;
3184 return MSVCR120_atanh(x
);
3188 /*********************************************************************
3189 * atanhl (MSVCR120.@)
3191 LDOUBLE CDECL
MSVCR120_atanhl(LDOUBLE x
)
3193 return MSVCR120_atanh(x
);
3196 /*********************************************************************
3198 * scalbn (MSVCR120.@)
3199 * scalbln (MSVCR120.@)
3201 double CDECL
MSVCRT__scalb(double num
, MSVCRT_long power
)
3203 return MSVCRT_ldexp(num
, power
);
3206 /*********************************************************************
3207 * _scalbf (MSVCRT.@)
3208 * scalbnf (MSVCR120.@)
3209 * scalblnf (MSVCR120.@)
3211 float CDECL
MSVCRT__scalbf(float num
, MSVCRT_long power
)
3213 return MSVCRT_ldexp(num
, power
);
3216 /*********************************************************************
3217 * scalbnl (MSVCR120.@)
3218 * scalblnl (MSVCR120.@)
3220 LDOUBLE CDECL
MSVCR120_scalbnl(LDOUBLE num
, MSVCRT_long power
)
3222 return MSVCRT__scalb(num
, power
);
3225 /*********************************************************************
3226 * remainder (MSVCR120.@)
3228 double CDECL
MSVCR120_remainder(double x
, double y
)
3230 #ifdef HAVE_REMAINDER
3231 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3232 if(!finite(x
)) *MSVCRT__errno() = MSVCRT_EDOM
;
3233 if(isnan(y
) || y
==0.0) *MSVCRT__errno() = MSVCRT_EDOM
;
3234 return remainder(x
, y
);
3236 FIXME( "not implemented\n" );
3241 /*********************************************************************
3242 * remainderf (MSVCR120.@)
3244 float CDECL
MSVCR120_remainderf(float x
, float y
)
3246 #ifdef HAVE_REMAINDERF
3247 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3248 if(!finitef(x
)) *MSVCRT__errno() = MSVCRT_EDOM
;
3249 if(isnanf(y
) || y
==0.0f
) *MSVCRT__errno() = MSVCRT_EDOM
;
3250 return remainderf(x
, y
);
3252 FIXME( "not implemented\n" );
3257 /*********************************************************************
3258 * remainderl (MSVCR120.@)
3260 LDOUBLE CDECL
MSVCR120_remainderl(LDOUBLE x
, LDOUBLE y
)
3262 return MSVCR120_remainder(x
, y
);
3265 /*********************************************************************
3266 * lgamma (MSVCR120.@)
3268 double CDECL
MSVCR120_lgamma(double x
)
3273 FIXME( "not implemented\n" );
3278 /*********************************************************************
3279 * lgammaf (MSVCR120.@)
3281 float CDECL
MSVCR120_lgammaf(float x
)
3286 FIXME( "not implemented\n" );
3291 /*********************************************************************
3292 * lgammal (MSVCR120.@)
3294 LDOUBLE CDECL
MSVCR120_lgammal(LDOUBLE x
)
3296 return MSVCR120_lgamma(x
);
3299 /*********************************************************************
3302 double CDECL
MSVCR120_nan(const char *tagp
)
3304 /* Windows ignores input (MSDN) */
3308 /*********************************************************************
3311 float CDECL
MSVCR120_nanf(const char *tagp
)
3316 /*********************************************************************
3317 * _except1 (MSVCR120.@)
3319 * - find meaning of ignored cw and operation bits
3322 double CDECL
_except1(DWORD fpe
, _FP_OPERATION_CODE op
, double arg
, double res
, DWORD cw
, void *unk
)
3324 ULONG_PTR exception_arg
;
3325 DWORD exception
= 0;
3330 TRACE("(%x %x %lf %lf %x %p)\n", fpe
, op
, arg
, res
, cw
, unk
);
3333 cw
= ((cw
>> 7) & 0x3f) | ((cw
>> 3) & 0xc00);
3335 operation
= op
<< 5;
3336 exception_arg
= (ULONG_PTR
)&operation
;
3338 MSVCRT_fegetenv(&env
);
3340 if (fpe
& 0x1) { /* overflow */
3341 if ((fpe
== 0x1 && (cw
& 0x8)) || (fpe
==0x11 && (cw
& 0x28))) {
3342 /* 32-bit version also sets SW_INEXACT here */
3343 env
.status
|= MSVCRT__SW_OVERFLOW
;
3344 if (fpe
& 0x10) env
.status
|= MSVCRT__SW_INEXACT
;
3345 res
= signbit(res
) ? -INFINITY
: INFINITY
;
3347 exception
= EXCEPTION_FLT_OVERFLOW
;
3349 } else if (fpe
& 0x2) { /* underflow */
3350 if ((fpe
== 0x2 && (cw
& 0x10)) || (fpe
==0x12 && (cw
& 0x30))) {
3351 env
.status
|= MSVCRT__SW_UNDERFLOW
;
3352 if (fpe
& 0x10) env
.status
|= MSVCRT__SW_INEXACT
;
3353 res
= signbit(res
) ? -0.0 : 0.0;
3355 exception
= EXCEPTION_FLT_UNDERFLOW
;
3357 } else if (fpe
& 0x4) { /* zerodivide */
3358 if ((fpe
== 0x4 && (cw
& 0x4)) || (fpe
==0x14 && (cw
& 0x24))) {
3359 env
.status
|= MSVCRT__SW_ZERODIVIDE
;
3360 if (fpe
& 0x10) env
.status
|= MSVCRT__SW_INEXACT
;
3362 exception
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
3364 } else if (fpe
& 0x8) { /* invalid */
3365 if (fpe
== 0x8 && (cw
& 0x1)) {
3366 env
.status
|= MSVCRT__SW_INVALID
;
3368 exception
= EXCEPTION_FLT_INVALID_OPERATION
;
3370 } else if (fpe
& 0x10) { /* inexact */
3371 if (fpe
== 0x10 && (cw
& 0x20)) {
3372 env
.status
|= MSVCRT__SW_INEXACT
;
3374 exception
= EXCEPTION_FLT_INEXACT_RESULT
;
3380 MSVCRT_fesetenv(&env
);
3382 RaiseException(exception
, 0, 1, &exception_arg
);
3384 if (cw
& 0x1) fpword
|= MSVCRT__EM_INVALID
;
3385 if (cw
& 0x2) fpword
|= MSVCRT__EM_DENORMAL
;
3386 if (cw
& 0x4) fpword
|= MSVCRT__EM_ZERODIVIDE
;
3387 if (cw
& 0x8) fpword
|= MSVCRT__EM_OVERFLOW
;
3388 if (cw
& 0x10) fpword
|= MSVCRT__EM_UNDERFLOW
;
3389 if (cw
& 0x20) fpword
|= MSVCRT__EM_INEXACT
;
3392 case 0xc00: fpword
|= MSVCRT__RC_UP
|MSVCRT__RC_DOWN
; break;
3393 case 0x800: fpword
|= MSVCRT__RC_UP
; break;
3394 case 0x400: fpword
|= MSVCRT__RC_DOWN
; break;
3398 case 0x0: fpword
|= MSVCRT__PC_24
; break;
3399 case 0x200: fpword
|= MSVCRT__PC_53
; break;
3400 case 0x300: fpword
|= MSVCRT__PC_64
; break;
3402 if (cw
& 0x1000) fpword
|= MSVCRT__IC_AFFINE
;
3403 _control87(fpword
, 0xffffffff);