msvcrt: Set errno through the _matherr function.
[wine.git] / dlls / msvcrt / math.c
bloba94c34ac80e1bfb7593d829ba566ac5cb8a4abb4
1 /*
2 * msvcrt.dll math functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include <stdio.h>
24 #define __USE_ISOC9X 1
25 #define __USE_ISOC99 1
26 #include <math.h>
27 #ifdef HAVE_IEEEFP_H
28 #include <ieeefp.h>
29 #endif
31 #include "msvcrt.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37 #ifndef HAVE_FINITEF
38 #define finitef(x) isfinite(x)
39 #endif
41 #ifndef HAVE_ISNANF
42 #ifdef HAVE_ISNAN
43 #define isnanf(x) isnan(x)
44 #else
45 #define isnanf(x) 0
46 #endif
47 #endif
49 /* FIXME: Does not work with -NAN and -0. */
50 #ifndef signbit
51 #define signbit(x) ((x) < 0)
52 #endif
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 /*********************************************************************
73 * _matherr (MSVCRT.@)
75 int CDECL MSVCRT__matherr(struct MSVCRT__exception *e)
77 int ret;
79 if (e)
80 TRACE("(%p = {%d, \"%s\", %g, %g, %g})\n", e, e->type, e->name, e->arg1, e->arg2, e->retval);
81 else
82 TRACE("(null)\n");
84 if (MSVCRT_default_matherr_func)
86 ret = MSVCRT_default_matherr_func(e);
87 if (ret) return ret;
90 switch (e->type)
92 case _DOMAIN:
93 *MSVCRT__errno() = MSVCRT_EDOM;
94 break;
95 case _SING:
96 case _OVERFLOW:
97 *MSVCRT__errno() = MSVCRT_ERANGE;
98 break;
99 case _UNDERFLOW:
100 /* don't set errno */
101 break;
102 default:
103 ERR("Unhandled math error!\n");
106 return 0;
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;
130 return sse2_enabled;
133 #ifdef _WIN64
134 /*********************************************************************
135 * _set_FMA3_enable (MSVCR120.@)
137 int CDECL MSVCRT__set_FMA3_enable(int flag)
139 FIXME("(%x) stub\n", flag);
140 return 0;
142 #endif
144 #if defined(__x86_64__) || defined(__arm__) || _MSVCR_VER>=120
146 /*********************************************************************
147 * _chgsignf (MSVCRT.@)
149 float CDECL MSVCRT__chgsignf( float num )
151 /* FIXME: +-infinity,Nan not tested */
152 return -num;
155 /*********************************************************************
156 * _copysignf (MSVCRT.@)
158 float CDECL MSVCRT__copysignf( float num, float sign )
160 if (signbit(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 );
174 #endif
175 #if defined(__x86_64__) || defined(__arm__)
177 /*********************************************************************
178 * _finitef (MSVCRT.@)
180 int CDECL MSVCRT__finitef( float num )
182 return finitef(num) != 0; /* See comment for _isnan() */
185 /*********************************************************************
186 * _isnanf (MSVCRT.@)
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 /*********************************************************************
197 * _logbf (MSVCRT.@)
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);
204 return 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);
219 return 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);
229 return 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);
239 return 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);
249 return ret;
252 /*********************************************************************
253 * MSVCRT_cosf (MSVCRT.@)
255 float CDECL MSVCRT_cosf( float x )
257 float ret = cosf(x);
258 if (!finitef(x)) math_error(_DOMAIN, "cosf", x, 0, ret);
259 return 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);
269 return ret;
272 /*********************************************************************
273 * MSVCRT_expf (MSVCRT.@)
275 float CDECL MSVCRT_expf( float x )
277 float ret = expf(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);
281 return 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);
291 return ret;
294 /*********************************************************************
295 * MSVCRT_logf (MSVCRT.@)
297 float CDECL MSVCRT_logf( float x )
299 float ret = logf(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);
302 return 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);
313 return 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 */
322 float z = powf(x,y);
323 if (!finitef(z)) math_error(_DOMAIN, "powf", x, 0, z);
324 return z;
327 /*********************************************************************
328 * MSVCRT_sinf (MSVCRT.@)
330 float CDECL MSVCRT_sinf( float x )
332 float ret = sinf(x);
333 if (!finitef(x)) math_error(_DOMAIN, "sinf", x, 0, ret);
334 return 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);
344 return 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);
354 return ret;
357 /*********************************************************************
358 * MSVCRT_tanf (MSVCRT.@)
360 float CDECL MSVCRT_tanf( float x )
362 float ret = tanf(x);
363 if (!finitef(x)) math_error(_DOMAIN, "tanf", x, 0, ret);
364 return 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);
374 return ret;
377 /*********************************************************************
378 * ceilf (MSVCRT.@)
380 float CDECL MSVCRT_ceilf( float x )
382 return ceilf(x);
385 /*********************************************************************
386 * fabsf (MSVCRT.@)
388 float CDECL MSVCRT_fabsf( float x )
390 return fabsf(x);
393 /*********************************************************************
394 * floorf (MSVCRT.@)
396 float CDECL MSVCRT_floorf( float x )
398 return floorf(x);
401 /*********************************************************************
402 * frexpf (MSVCRT.@)
404 float CDECL MSVCRT_frexpf( float x, int *exp )
406 return frexpf( x, exp );
409 /*********************************************************************
410 * modff (MSVCRT.@)
412 float CDECL MSVCRT_modff( float x, float *iptr )
414 return modff( x, iptr );
417 #endif
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);
431 return 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);
441 return 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);
451 return 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);
461 return ret;
464 /*********************************************************************
465 * MSVCRT_cos (MSVCRT.@)
467 double CDECL MSVCRT_cos( double x )
469 double ret = cos(x);
470 if (!isfinite(x)) math_error(_DOMAIN, "cos", x, 0, ret);
471 return 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);
481 return ret;
484 /*********************************************************************
485 * MSVCRT_exp (MSVCRT.@)
487 double CDECL MSVCRT_exp( double x )
489 double ret = exp(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);
493 return 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);
503 return ret;
506 /*********************************************************************
507 * MSVCRT_log (MSVCRT.@)
509 double CDECL MSVCRT_log( double x )
511 double ret = log(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);
514 return 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);
525 return 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 */
534 double z = pow(x,y);
535 if (!isfinite(z)) math_error(_DOMAIN, "pow", x, y, z);
536 return z;
539 /*********************************************************************
540 * MSVCRT_sin (MSVCRT.@)
542 double CDECL MSVCRT_sin( double x )
544 double ret = sin(x);
545 if (!isfinite(x)) math_error(_DOMAIN, "sin", x, 0, ret);
546 return 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);
556 return 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);
566 return ret;
569 /*********************************************************************
570 * MSVCRT_tan (MSVCRT.@)
572 double CDECL MSVCRT_tan( double x )
574 double ret = tan(x);
575 if (!isfinite(x)) math_error(_DOMAIN, "tan", x, 0, ret);
576 return 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);
586 return 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 /*********************************************************************
599 * _CIacos (MSVCRT.@)
601 double CDECL _CIacos(void)
603 FPU_DOUBLE(x);
604 return MSVCRT_acos(x);
607 /*********************************************************************
608 * _CIasin (MSVCRT.@)
610 double CDECL _CIasin(void)
612 FPU_DOUBLE(x);
613 return MSVCRT_asin(x);
616 /*********************************************************************
617 * _CIatan (MSVCRT.@)
619 double CDECL _CIatan(void)
621 FPU_DOUBLE(x);
622 return MSVCRT_atan(x);
625 /*********************************************************************
626 * _CIatan2 (MSVCRT.@)
628 double CDECL _CIatan2(void)
630 FPU_DOUBLES(x,y);
631 return MSVCRT_atan2(x,y);
634 /*********************************************************************
635 * _CIcos (MSVCRT.@)
637 double CDECL _CIcos(void)
639 FPU_DOUBLE(x);
640 return MSVCRT_cos(x);
643 /*********************************************************************
644 * _CIcosh (MSVCRT.@)
646 double CDECL _CIcosh(void)
648 FPU_DOUBLE(x);
649 return MSVCRT_cosh(x);
652 /*********************************************************************
653 * _CIexp (MSVCRT.@)
655 double CDECL _CIexp(void)
657 FPU_DOUBLE(x);
658 return MSVCRT_exp(x);
661 /*********************************************************************
662 * _CIfmod (MSVCRT.@)
664 double CDECL _CIfmod(void)
666 FPU_DOUBLES(x,y);
667 return MSVCRT_fmod(x,y);
670 /*********************************************************************
671 * _CIlog (MSVCRT.@)
673 double CDECL _CIlog(void)
675 FPU_DOUBLE(x);
676 return MSVCRT_log(x);
679 /*********************************************************************
680 * _CIlog10 (MSVCRT.@)
682 double CDECL _CIlog10(void)
684 FPU_DOUBLE(x);
685 return MSVCRT_log10(x);
688 /*********************************************************************
689 * _CIpow (MSVCRT.@)
691 double CDECL _CIpow(void)
693 FPU_DOUBLES(x,y);
694 return MSVCRT_pow(x,y);
697 /*********************************************************************
698 * _CIsin (MSVCRT.@)
700 double CDECL _CIsin(void)
702 FPU_DOUBLE(x);
703 return MSVCRT_sin(x);
706 /*********************************************************************
707 * _CIsinh (MSVCRT.@)
709 double CDECL _CIsinh(void)
711 FPU_DOUBLE(x);
712 return MSVCRT_sinh(x);
715 /*********************************************************************
716 * _CIsqrt (MSVCRT.@)
718 double CDECL _CIsqrt(void)
720 FPU_DOUBLE(x);
721 return MSVCRT_sqrt(x);
724 /*********************************************************************
725 * _CItan (MSVCRT.@)
727 double CDECL _CItan(void)
729 FPU_DOUBLE(x);
730 return MSVCRT_tan(x);
733 /*********************************************************************
734 * _CItanh (MSVCRT.@)
736 double CDECL _CItanh(void)
738 FPU_DOUBLE(x);
739 return MSVCRT_tanh(x);
742 /*********************************************************************
743 * _ftol (MSVCRT.@)
745 LONGLONG CDECL MSVCRT__ftol(void)
747 FPU_DOUBLE(x);
748 return (LONGLONG)x;
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;
782 #else
783 if (!isfinite(num))
784 return MSVCRT__FPCLASS_QNAN;
785 return num == 0.0 ? MSVCRT__FPCLASS_PZ : (num < 0 ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN);
786 #endif
789 /*********************************************************************
790 * _rotl (MSVCRT.@)
792 unsigned int CDECL _rotl(unsigned int num, int shift)
794 shift &= 31;
795 return (num << shift) | (num >> (32-shift));
798 /*********************************************************************
799 * _lrotl (MSVCRT.@)
801 MSVCRT_ulong CDECL MSVCRT__lrotl(MSVCRT_ulong num, int shift)
803 shift &= 0x1f;
804 return (num << shift) | (num >> (32-shift));
807 /*********************************************************************
808 * _lrotr (MSVCRT.@)
810 MSVCRT_ulong CDECL MSVCRT__lrotr(MSVCRT_ulong num, int shift)
812 shift &= 0x1f;
813 return (num >> shift) | (num << (32-shift));
816 /*********************************************************************
817 * _rotr (MSVCRT.@)
819 unsigned int CDECL _rotr(unsigned int num, int shift)
821 shift &= 0x1f;
822 return (num >> shift) | (num << (32-shift));
825 /*********************************************************************
826 * _rotl64 (MSVCRT.@)
828 unsigned __int64 CDECL _rotl64(unsigned __int64 num, int shift)
830 shift &= 63;
831 return (num << shift) | (num >> (64-shift));
834 /*********************************************************************
835 * _rotr64 (MSVCRT.@)
837 unsigned __int64 CDECL _rotr64(unsigned __int64 num, int shift)
839 shift &= 63;
840 return (num >> shift) | (num << (64-shift));
843 /*********************************************************************
844 * abs (MSVCRT.@)
846 int CDECL MSVCRT_abs( int n )
848 return n >= 0 ? n : -n;
851 /*********************************************************************
852 * labs (MSVCRT.@)
854 MSVCRT_long CDECL MSVCRT_labs( MSVCRT_long n )
856 return n >= 0 ? n : -n;
859 /*********************************************************************
860 * llabs (MSVCRT.@)
862 MSVCRT_longlong CDECL MSVCRT_llabs( MSVCRT_longlong n )
864 return n >= 0 ? n : -n;
867 /*********************************************************************
868 * _abs64 (MSVCRT.@)
870 __int64 CDECL _abs64( __int64 n )
872 return n >= 0 ? n : -n;
875 /*********************************************************************
876 * _logb (MSVCRT.@)
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);
883 return ret;
886 /*********************************************************************
887 * _hypot (MSVCRT.@)
889 double CDECL _hypot(double x, double y)
891 /* FIXME: errno handling */
892 return hypot( x, y );
895 /*********************************************************************
896 * _hypotf (MSVCRT.@)
898 float CDECL MSVCRT__hypotf(float x, float y)
900 /* FIXME: errno handling */
901 return hypotf( x, y );
904 /*********************************************************************
905 * ceil (MSVCRT.@)
907 double CDECL MSVCRT_ceil( double x )
909 return ceil(x);
912 /*********************************************************************
913 * floor (MSVCRT.@)
915 double CDECL MSVCRT_floor( double x )
917 return floor(x);
920 /*********************************************************************
921 * fabs (MSVCRT.@)
923 double CDECL MSVCRT_fabs( double x )
925 return fabs(x);
928 /*********************************************************************
929 * frexp (MSVCRT.@)
931 double CDECL MSVCRT_frexp( double x, int *exp )
933 return frexp( x, exp );
936 /*********************************************************************
937 * modf (MSVCRT.@)
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 )
952 #ifdef __GNUC__
953 unsigned int flags;
954 unsigned long fpword;
956 if (x86_sw)
958 __asm__ __volatile__( "fstsw %0" : "=m" (fpword) );
959 flags = 0;
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;
966 *x86_sw = flags;
969 if (!sse2_sw) return;
971 if (sse2_supported)
973 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
974 flags = 0;
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;
981 *sse2_sw = flags;
983 else *sse2_sw = 0;
984 #else
985 FIXME( "not implemented\n" );
986 #endif
988 #endif
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;
1001 #else
1002 FIXME( "not implemented\n" );
1003 return 0;
1004 #endif
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;
1024 if (sse2_supported)
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;
1033 fpword &= ~0x3f;
1034 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1036 #else
1037 FIXME( "not implemented\n" );
1038 #endif
1039 return flags;
1042 /*********************************************************************
1043 * __fpecode (MSVCRT.@)
1045 int * CDECL __fpecode(void)
1047 return &msvcrt_get_thread_data()->fpecode;
1050 /*********************************************************************
1051 * ldexp (MSVCRT.@)
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 */
1063 return z;
1066 /*********************************************************************
1067 * _cabs (MSVCRT.@)
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 */
1080 return -num;
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 )
1092 #ifdef __GNUC__
1093 unsigned long fpword;
1094 unsigned int flags;
1096 if (x86_cw)
1098 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
1100 /* Convert into mask constants */
1101 flags = 0;
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 );
1123 if (mask)
1125 flags = (flags & ~mask) | (newval & mask);
1127 /* Convert (masked) value back to fp word */
1128 fpword = 0;
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) );
1151 *x86_cw = flags;
1154 if (!sse2_cw) return 1;
1156 if (sse2_supported)
1158 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1160 /* Convert into mask constants */
1161 flags = 0;
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 );
1182 if (mask)
1184 flags = (flags & ~mask) | (newval & mask);
1186 /* Convert (masked) value back to fp word */
1187 fpword = 0;
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) );
1208 *sse2_cw = flags;
1210 else *sse2_cw = 0;
1212 return 1;
1213 #else
1214 FIXME( "not implemented\n" );
1215 return 0;
1216 #endif
1218 #endif
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;
1231 return x86_cw;
1232 #else
1233 FIXME( "not implemented\n" );
1234 return 0;
1235 #endif
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);
1261 unsigned int val;
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;
1270 return 0;
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();
1281 return 0;
1284 /*********************************************************************
1285 * __fpe_flt_rounds (UCRTBASE.@)
1287 int CDECL __fpe_flt_rounds(void)
1289 unsigned int fpc = _controlfp(0, 0) & MSVCRT__RC_CHOP;
1291 TRACE("()\n");
1293 switch(fpc) {
1294 case MSVCRT__RC_CHOP: return 0;
1295 case MSVCRT__RC_NEAR: return 1;
1296 #ifdef _WIN64
1297 case MSVCRT__RC_UP: return 3;
1298 default: return 2;
1299 #else
1300 case MSVCRT__RC_UP: return 2;
1301 default: return 3;
1302 #endif
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))
1320 return 1;
1321 _controlfp(round_mode, MSVCRT__RC_CHOP);
1322 return 0;
1325 /*********************************************************************
1326 * _copysign (MSVCRT.@)
1328 double CDECL MSVCRT__copysign(double num, double sign)
1330 if (signbit(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) );
1351 if (sse2_supported)
1353 const unsigned long sse2_cw = 0x1f80;
1354 __asm__ __volatile__( "ldmxcsr %0" : : "m" (sse2_cw) );
1356 #else
1357 FIXME( "not implemented\n" );
1358 #endif
1361 /*********************************************************************
1362 * fesetenv (MSVCR120.@)
1364 int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
1366 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1367 struct {
1368 WORD control_word;
1369 WORD unused1;
1370 WORD status_word;
1371 WORD unused2;
1372 WORD tag_word;
1373 WORD unused3;
1374 DWORD instruction_pointer;
1375 WORD code_segment;
1376 WORD unused4;
1377 DWORD operand_addr;
1378 WORD data_segment;
1379 WORD unused5;
1380 } fenv;
1382 TRACE( "(%p)\n", env );
1384 if (!env->control && !env->status) {
1385 _fpreset();
1386 return 0;
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)" );
1408 if (sse2_supported)
1410 DWORD fpword;
1412 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1413 fpword &= ~0x1e80;
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) );
1422 return 0;
1423 #else
1424 FIXME( "not implemented\n" );
1425 #endif
1426 return 1;
1429 /*********************************************************************
1430 * _isnan (MSVCRT.@)
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 /*********************************************************************
1441 * _j0 (MSVCRT.@)
1443 double CDECL MSVCRT__j0(double num)
1445 /* FIXME: errno handling */
1446 return j0(num);
1449 /*********************************************************************
1450 * _j1 (MSVCRT.@)
1452 double CDECL MSVCRT__j1(double num)
1454 /* FIXME: errno handling */
1455 return j1(num);
1458 /*********************************************************************
1459 * _jn (MSVCRT.@)
1461 double CDECL MSVCRT__jn(int n, double num)
1463 /* FIXME: errno handling */
1464 return jn(n, num);
1467 /*********************************************************************
1468 * _y0 (MSVCRT.@)
1470 double CDECL MSVCRT__y0(double num)
1472 double retval;
1473 if (!isfinite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1474 retval = y0(num);
1475 if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1477 *MSVCRT__errno() = MSVCRT_EDOM;
1478 retval = sqrt(-1);
1480 return retval;
1483 /*********************************************************************
1484 * _y1 (MSVCRT.@)
1486 double CDECL MSVCRT__y1(double num)
1488 double retval;
1489 if (!isfinite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1490 retval = y1(num);
1491 if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1493 *MSVCRT__errno() = MSVCRT_EDOM;
1494 retval = sqrt(-1);
1496 return retval;
1499 /*********************************************************************
1500 * _yn (MSVCRT.@)
1502 double CDECL MSVCRT__yn(int order, double num)
1504 double retval;
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;
1510 retval = sqrt(-1);
1512 return retval;
1515 /*********************************************************************
1516 * _nearbyint (MSVCRT.@)
1518 double CDECL MSVCRT_nearbyint(double num)
1520 #ifdef HAVE_NEARBYINT
1521 return nearbyint(num);
1522 #else
1523 return num >= 0 ? floor(num + 0.5) : ceil(num - 0.5);
1524 #endif
1527 /*********************************************************************
1528 * _nearbyintf (MSVCRT.@)
1530 float CDECL MSVCRT_nearbyintf(float num)
1532 #ifdef HAVE_NEARBYINTF
1533 return nearbyintf(num);
1534 #else
1535 return MSVCRT_nearbyint(num);
1536 #endif
1539 /*********************************************************************
1540 * _nextafter (MSVCRT.@)
1542 double CDECL MSVCRT__nextafter(double num, double next)
1544 double retval;
1545 if (!isfinite(num) || !isfinite(next)) *MSVCRT__errno() = MSVCRT_EDOM;
1546 retval = nextafter(num,next);
1547 return retval;
1550 /*********************************************************************
1551 * _ecvt (MSVCRT.@)
1553 char * CDECL MSVCRT__ecvt( double number, int ndigits, int *decpt, int *sign )
1555 int prec, len;
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 */
1564 if( number < 0) {
1565 *sign = TRUE;
1566 number = -number;
1567 } else
1568 *sign = FALSE;
1569 /* handle cases with zero ndigits or less */
1570 prec = ndigits;
1571 if( prec < 1) prec = 2;
1572 len = snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
1573 /* take the decimal "point away */
1574 if( prec != 1)
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);
1580 (*decpt)++;
1581 /* adjust for some border cases */
1582 if( data->efcvt_buffer[0] == '0')/* value is zero */
1583 *decpt = 0;
1584 /* handle cases with zero ndigits or less */
1585 if( ndigits < 1){
1586 if( data->efcvt_buffer[ 0] >= '5')
1587 (*decpt)++;
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 )
1599 int prec, len;
1600 char *result;
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';
1615 (*decpt) = 1;
1616 if(number == -HUGE_VAL)
1617 (*sign) = 1;
1618 else
1619 (*sign) = 0;
1620 return 0;
1622 /* handle cases with zero ndigits or less */
1623 prec = ndigits;
1624 if( prec < 1) prec = 2;
1625 result = MSVCRT_malloc(prec + 7);
1627 if( number < 0) {
1628 *sign = TRUE;
1629 number = -number;
1630 } else
1631 *sign = FALSE;
1632 len = snprintf(result, prec + 7, "%.*le", prec - 1, number);
1633 /* take the decimal "point away */
1634 if( prec != 1)
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);
1640 (*decpt)++;
1641 /* adjust for some border cases */
1642 if( result[0] == '0')/* value is zero */
1643 *decpt = 0;
1644 /* handle cases with zero ndigits or less */
1645 if( ndigits < 1){
1646 if( result[ 0] >= '5')
1647 (*decpt)++;
1648 result[ 0] = '\0';
1650 memcpy( buffer, result, max(ndigits + 1, 1) );
1651 MSVCRT_free( result );
1652 return 0;
1655 /***********************************************************************
1656 * _fcvt (MSVCRT.@)
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 */
1668 if (number < 0)
1670 *sign = 1;
1671 number = -number;
1672 } else *sign = 0;
1674 stop = snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1675 ptr1 = buf;
1676 ptr2 = data->efcvt_buffer;
1677 first = NULL;
1678 dec1 = 0;
1679 dec2 = 0;
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 */
1690 if (ndigits < 1) {
1691 stop += ndigits;
1694 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1695 while (*ptr1 != '\0' && *ptr1 != '.') {
1696 if (!first) first = ptr2;
1697 if ((ptr1 - buf) < stop) {
1698 *ptr2++ = *ptr1++;
1699 } else {
1700 ptr1++;
1702 dec1++;
1705 if (ndigits > 0) {
1706 ptr1++;
1707 if (!first) {
1708 while (*ptr1 == '0') { /* Process leading zeroes */
1709 *ptr2++ = *ptr1++;
1710 dec1--;
1713 while (*ptr1 != '\0') {
1714 if (!first) first = ptr2;
1715 *ptr2++ = *ptr1++;
1719 *ptr2 = '\0';
1721 /* We never found a non-zero digit, then our number is either
1722 * smaller than the requested precision, or 0.0 */
1723 if (!first) {
1724 if (number > 0.0) {
1725 first = ptr2;
1726 } else {
1727 first = data->efcvt_buffer;
1728 dec1 = 0;
1732 *decpt = dec2 ? dec2 : dec1;
1733 return first;
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;
1751 if (number < 0)
1753 *sign = 1;
1754 number = -number;
1755 } else *sign = 0;
1757 stop = snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1758 ptr1 = buf;
1759 ptr2 = outbuffer;
1760 first = NULL;
1761 dec1 = 0;
1762 dec2 = 0;
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 */
1773 if (ndigits < 1) {
1774 stop += ndigits;
1777 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1778 while (*ptr1 != '\0' && *ptr1 != '.') {
1779 if (!first) first = ptr2;
1780 if ((ptr1 - buf) < stop) {
1781 if (size > 1) {
1782 *ptr2++ = *ptr1++;
1783 size--;
1785 } else {
1786 ptr1++;
1788 dec1++;
1791 if (ndigits > 0) {
1792 ptr1++;
1793 if (!first) {
1794 while (*ptr1 == '0') { /* Process leading zeroes */
1795 if (number == 0.0 && size > 1) {
1796 *ptr2++ = '0';
1797 size--;
1799 ptr1++;
1800 dec1--;
1803 while (*ptr1 != '\0') {
1804 if (!first) first = ptr2;
1805 if (size > 1) {
1806 *ptr2++ = *ptr1++;
1807 size--;
1812 *ptr2 = '\0';
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))
1817 dec1 = 0;
1819 *decpt = dec2 ? dec2 : dec1;
1820 return 0;
1823 /***********************************************************************
1824 * _gcvt (MSVCRT.@)
1826 char * CDECL MSVCRT__gcvt( double number, int ndigit, char *buff )
1828 if(!buff) {
1829 *MSVCRT__errno() = MSVCRT_EINVAL;
1830 return NULL;
1833 if(ndigit < 0) {
1834 *MSVCRT__errno() = MSVCRT_ERANGE;
1835 return NULL;
1838 MSVCRT_sprintf(buff, "%.*g", ndigit, number);
1839 return buff;
1842 /***********************************************************************
1843 * _gcvt_s (MSVCRT.@)
1845 int CDECL MSVCRT__gcvt_s(char *buff, MSVCRT_size_t size, double number, int digits)
1847 int len;
1849 if(!buff) {
1850 *MSVCRT__errno() = MSVCRT_EINVAL;
1851 return MSVCRT_EINVAL;
1854 if( digits<0 || digits>=size) {
1855 if(size)
1856 buff[0] = '\0';
1858 *MSVCRT__errno() = MSVCRT_ERANGE;
1859 return MSVCRT_ERANGE;
1862 len = MSVCRT__scprintf("%.*g", digits, number);
1863 if(len > size) {
1864 buff[0] = '\0';
1865 *MSVCRT__errno() = MSVCRT_ERANGE;
1866 return MSVCRT_ERANGE;
1869 MSVCRT_sprintf(buff, "%.*g", digits, number);
1870 return 0;
1873 #include <stdlib.h> /* div_t, ldiv_t */
1875 /*********************************************************************
1876 * div (MSVCRT.@)
1877 * VERSION
1878 * [i386] Windows binary compatible - returns the struct in eax/edx.
1880 #ifdef __i386__
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;
1886 #else
1887 /*********************************************************************
1888 * div (MSVCRT.@)
1889 * VERSION
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);
1895 MSVCRT_div_t ret;
1896 ret.quot = dt.quot;
1897 ret.rem = dt.rem;
1899 return ret;
1902 #endif /* ifdef __i386__ */
1905 /*********************************************************************
1906 * ldiv (MSVCRT.@)
1907 * VERSION
1908 * [i386] Windows binary compatible - returns the struct in eax/edx.
1910 #ifdef __i386__
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;
1916 #else
1917 /*********************************************************************
1918 * ldiv (MSVCRT.@)
1919 * VERSION
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);
1926 MSVCRT_ldiv_t ret;
1927 ret.quot = result.quot;
1928 ret.rem = result.rem;
1930 return ret;
1932 #endif /* ifdef __i386__ */
1934 /*********************************************************************
1935 * lldiv (MSVCRT.@)
1937 MSVCRT_lldiv_t CDECL MSVCRT_lldiv(MSVCRT_longlong num, MSVCRT_longlong denom)
1939 MSVCRT_lldiv_t ret;
1941 ret.quot = num / denom;
1942 ret.rem = num % denom;
1944 return ret;
1947 #ifdef __i386__
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.@)
1958 * NOTE
1959 * I _think_ this function is intended to work around the Pentium
1960 * fdiv bug.
1962 void __stdcall _adj_fdiv_m16i( short arg )
1964 TRACE("(): stub\n");
1967 /***********************************************************************
1968 * _adj_fdiv_m32 (MSVCRT.@)
1970 * NOTE
1971 * I _think_ this function is intended to work around the Pentium
1972 * fdiv bug.
1974 void __stdcall _adj_fdiv_m32( unsigned int arg )
1976 TRACE("(): stub\n");
1979 /***********************************************************************
1980 * _adj_fdiv_m32i (MSVCRT.@)
1982 * NOTE
1983 * I _think_ this function is intended to work around the Pentium
1984 * fdiv bug.
1986 void __stdcall _adj_fdiv_m32i( int arg )
1988 TRACE("(): stub\n");
1991 /***********************************************************************
1992 * _adj_fdiv_m64 (MSVCRT.@)
1994 * NOTE
1995 * I _think_ this function is intended to work around the Pentium
1996 * fdiv bug.
1998 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
2000 TRACE("(): stub\n");
2003 /***********************************************************************
2004 * _adj_fdiv_r (MSVCRT.@)
2005 * FIXME
2006 * This function is likely to have the wrong number of arguments.
2008 * NOTE
2009 * I _think_ this function is intended to work around the Pentium
2010 * fdiv bug.
2012 void _adj_fdiv_r(void)
2014 TRACE("(): stub\n");
2017 /***********************************************************************
2018 * _adj_fdivr_m16i (MSVCRT.@)
2020 * NOTE
2021 * I _think_ this function is intended to work around the Pentium
2022 * fdiv bug.
2024 void __stdcall _adj_fdivr_m16i( short arg )
2026 TRACE("(): stub\n");
2029 /***********************************************************************
2030 * _adj_fdivr_m32 (MSVCRT.@)
2032 * NOTE
2033 * I _think_ this function is intended to work around the Pentium
2034 * fdiv bug.
2036 void __stdcall _adj_fdivr_m32( unsigned int arg )
2038 TRACE("(): stub\n");
2041 /***********************************************************************
2042 * _adj_fdivr_m32i (MSVCRT.@)
2044 * NOTE
2045 * I _think_ this function is intended to work around the Pentium
2046 * fdiv bug.
2048 void __stdcall _adj_fdivr_m32i( int arg )
2050 TRACE("(): stub\n");
2053 /***********************************************************************
2054 * _adj_fdivr_m64 (MSVCRT.@)
2056 * NOTE
2057 * I _think_ this function is intended to work around the Pentium
2058 * fdiv bug.
2060 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
2062 TRACE("(): stub\n");
2065 /***********************************************************************
2066 * _adj_fpatan (MSVCRT.@)
2067 * FIXME
2068 * This function is likely to have the wrong number of arguments.
2070 * NOTE
2071 * I _think_ this function is intended to work around the Pentium
2072 * fdiv bug.
2074 void _adj_fpatan(void)
2076 TRACE("(): stub\n");
2079 /***********************************************************************
2080 * _adj_fprem (MSVCRT.@)
2081 * FIXME
2082 * This function is likely to have the wrong number of arguments.
2084 * NOTE
2085 * I _think_ this function is intended to work around the Pentium
2086 * fdiv bug.
2088 void _adj_fprem(void)
2090 TRACE("(): stub\n");
2093 /***********************************************************************
2094 * _adj_fprem1 (MSVCRT.@)
2095 * FIXME
2096 * This function is likely to have the wrong number of arguments.
2098 * NOTE
2099 * I _think_ this function is intended to work around the Pentium
2100 * fdiv bug.
2102 void _adj_fprem1(void)
2104 TRACE("(): stub\n");
2107 /***********************************************************************
2108 * _adj_fptan (MSVCRT.@)
2109 * FIXME
2110 * This function is likely to have the wrong number of arguments.
2112 * NOTE
2113 * I _think_ this function is intended to work around the Pentium
2114 * fdiv bug.
2116 void _adj_fptan(void)
2118 TRACE("(): stub\n");
2121 /***********************************************************************
2122 * _safe_fdiv (MSVCRT.@)
2123 * FIXME
2124 * This function is likely to have the wrong number of arguments.
2126 * NOTE
2127 * I _think_ this function is intended to work around the Pentium
2128 * fdiv bug.
2130 void _safe_fdiv(void)
2132 TRACE("(): stub\n");
2135 /***********************************************************************
2136 * _safe_fdivr (MSVCRT.@)
2137 * FIXME
2138 * This function is likely to have the wrong number of arguments.
2140 * NOTE
2141 * I _think_ this function is intended to work around the Pentium
2142 * fdiv bug.
2144 void _safe_fdivr(void)
2146 TRACE("(): stub\n");
2149 /***********************************************************************
2150 * _safe_fprem (MSVCRT.@)
2151 * FIXME
2152 * This function is likely to have the wrong number of arguments.
2154 * NOTE
2155 * I _think_ this function is intended to work around the Pentium
2156 * fdiv bug.
2158 void _safe_fprem(void)
2160 TRACE("(): stub\n");
2163 /***********************************************************************
2164 * _safe_fprem1 (MSVCRT.@)
2166 * FIXME
2167 * This function is likely to have the wrong number of arguments.
2169 * NOTE
2170 * I _think_ this function is intended to work around the Pentium
2171 * fdiv bug.
2173 void _safe_fprem1(void)
2175 TRACE("(): stub\n");
2178 /***********************************************************************
2179 * __libm_sse2_acos (MSVCRT.@)
2181 void __cdecl MSVCRT___libm_sse2_acos(void)
2183 double d;
2184 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2185 d = acos( d );
2186 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2189 /***********************************************************************
2190 * __libm_sse2_acosf (MSVCRT.@)
2192 void __cdecl MSVCRT___libm_sse2_acosf(void)
2194 float f;
2195 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2196 f = acosf( f );
2197 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2200 /***********************************************************************
2201 * __libm_sse2_asin (MSVCRT.@)
2203 void __cdecl MSVCRT___libm_sse2_asin(void)
2205 double d;
2206 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2207 d = asin( d );
2208 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2211 /***********************************************************************
2212 * __libm_sse2_asinf (MSVCRT.@)
2214 void __cdecl MSVCRT___libm_sse2_asinf(void)
2216 float f;
2217 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2218 f = asinf( f );
2219 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2222 /***********************************************************************
2223 * __libm_sse2_atan (MSVCRT.@)
2225 void __cdecl MSVCRT___libm_sse2_atan(void)
2227 double d;
2228 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2229 d = atan( d );
2230 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2233 /***********************************************************************
2234 * __libm_sse2_atan2 (MSVCRT.@)
2236 void __cdecl MSVCRT___libm_sse2_atan2(void)
2238 double d1, d2;
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)
2249 float f;
2250 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2251 f = atanf( f );
2252 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2255 /***********************************************************************
2256 * __libm_sse2_cos (MSVCRT.@)
2258 void __cdecl MSVCRT___libm_sse2_cos(void)
2260 double d;
2261 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2262 d = cos( d );
2263 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2266 /***********************************************************************
2267 * __libm_sse2_cosf (MSVCRT.@)
2269 void __cdecl MSVCRT___libm_sse2_cosf(void)
2271 float f;
2272 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2273 f = cosf( f );
2274 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2277 /***********************************************************************
2278 * __libm_sse2_exp (MSVCRT.@)
2280 void __cdecl MSVCRT___libm_sse2_exp(void)
2282 double d;
2283 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2284 d = exp( d );
2285 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2288 /***********************************************************************
2289 * __libm_sse2_expf (MSVCRT.@)
2291 void __cdecl MSVCRT___libm_sse2_expf(void)
2293 float f;
2294 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2295 f = expf( f );
2296 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2299 /***********************************************************************
2300 * __libm_sse2_log (MSVCRT.@)
2302 void __cdecl MSVCRT___libm_sse2_log(void)
2304 double d;
2305 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2306 d = log( d );
2307 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2310 /***********************************************************************
2311 * __libm_sse2_log10 (MSVCRT.@)
2313 void __cdecl MSVCRT___libm_sse2_log10(void)
2315 double d;
2316 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2317 d = log10( d );
2318 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2321 /***********************************************************************
2322 * __libm_sse2_log10f (MSVCRT.@)
2324 void __cdecl MSVCRT___libm_sse2_log10f(void)
2326 float f;
2327 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2328 f = log10f( f );
2329 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2332 /***********************************************************************
2333 * __libm_sse2_logf (MSVCRT.@)
2335 void __cdecl MSVCRT___libm_sse2_logf(void)
2337 float f;
2338 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2339 f = logf( f );
2340 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2343 /***********************************************************************
2344 * __libm_sse2_pow (MSVCRT.@)
2346 void __cdecl MSVCRT___libm_sse2_pow(void)
2348 double d1, d2;
2349 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2350 d1 = pow( d1, d2 );
2351 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2354 /***********************************************************************
2355 * __libm_sse2_powf (MSVCRT.@)
2357 void __cdecl MSVCRT___libm_sse2_powf(void)
2359 float f1, f2;
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)
2370 double d;
2371 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2372 d = sin( d );
2373 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2376 /***********************************************************************
2377 * __libm_sse2_sinf (MSVCRT.@)
2379 void __cdecl MSVCRT___libm_sse2_sinf(void)
2381 float f;
2382 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2383 f = sinf( f );
2384 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2387 /***********************************************************************
2388 * __libm_sse2_tan (MSVCRT.@)
2390 void __cdecl MSVCRT___libm_sse2_tan(void)
2392 double d;
2393 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2394 d = tan( d );
2395 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2398 /***********************************************************************
2399 * __libm_sse2_tanf (MSVCRT.@)
2401 void __cdecl MSVCRT___libm_sse2_tanf(void)
2403 float f;
2404 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2405 f = tanf( 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)
2414 double d;
2415 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2416 d = sqrt( d );
2417 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2420 #endif /* __i386__ */
2422 /*********************************************************************
2423 * cbrt (MSVCR120.@)
2425 double CDECL MSVCR120_cbrt(double x)
2427 #ifdef HAVE_CBRT
2428 return cbrt(x);
2429 #else
2430 return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0);
2431 #endif
2434 /*********************************************************************
2435 * cbrtf (MSVCR120.@)
2437 float CDECL MSVCR120_cbrtf(float x)
2439 #ifdef HAVE_CBRTF
2440 return cbrtf(x);
2441 #else
2442 return MSVCR120_cbrt(x);
2443 #endif
2446 /*********************************************************************
2447 * cbrtl (MSVCR120.@)
2449 LDOUBLE CDECL MSVCR120_cbrtl(LDOUBLE x)
2451 return MSVCR120_cbrt(x);
2454 /*********************************************************************
2455 * exp2 (MSVCR120.@)
2457 double CDECL MSVCR120_exp2(double x)
2459 #ifdef HAVE_EXP2
2460 double ret = exp2(x);
2461 #else
2462 double ret = pow(2, x);
2463 #endif
2464 if (isfinite(x) && !isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2465 return ret;
2468 /*********************************************************************
2469 * exp2f (MSVCR120.@)
2471 float CDECL MSVCR120_exp2f(float x)
2473 #ifdef HAVE_EXP2F
2474 float ret = exp2f(x);
2475 if (finitef(x) && !finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2476 return ret;
2477 #else
2478 return MSVCR120_exp2(x);
2479 #endif
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)
2495 #ifdef HAVE_EXPM1
2496 double ret = expm1(x);
2497 #else
2498 double ret = exp(x) - 1;
2499 #endif
2500 if (isfinite(x) && !isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2501 return ret;
2504 /*********************************************************************
2505 * expm1f (MSVCR120.@)
2507 float CDECL MSVCR120_expm1f(float x)
2509 #ifdef HAVE_EXPM1F
2510 float ret = expm1f(x);
2511 #else
2512 float ret = exp(x) - 1;
2513 #endif
2514 if (finitef(x) && !finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2515 return ret;
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;
2533 #ifdef HAVE_LOG1P
2534 return log1p(x);
2535 #else
2536 return log(1 + x);
2537 #endif
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;
2547 #ifdef HAVE_LOG1PF
2548 return log1pf(x);
2549 #else
2550 return log(1 + x);
2551 #endif
2554 /*********************************************************************
2555 * log1pl (MSVCR120.@)
2557 LDOUBLE CDECL MSVCR120_log1pl(LDOUBLE x)
2559 return MSVCR120_log1p(x);
2562 /*********************************************************************
2563 * log2 (MSVCR120.@)
2565 double CDECL MSVCR120_log2(double x)
2567 if (x < 0) *MSVCRT__errno() = MSVCRT_EDOM;
2568 else if (x == 0) *MSVCRT__errno() = MSVCRT_ERANGE;
2569 #ifdef HAVE_LOG2
2570 return log2(x);
2571 #else
2572 return log(x) / log(2);
2573 #endif
2576 /*********************************************************************
2577 * log2f (MSVCR120.@)
2579 float CDECL MSVCR120_log2f(float x)
2581 #ifdef HAVE_LOG2F
2582 if (x < 0) *MSVCRT__errno() = MSVCRT_EDOM;
2583 else if (x == 0) *MSVCRT__errno() = MSVCRT_ERANGE;
2584 return log2f(x);
2585 #else
2586 return MSVCR120_log2(x);
2587 #endif
2590 /*********************************************************************
2591 * log2l (MSVCR120.@)
2593 LDOUBLE CDECL MSVCR120_log2l(LDOUBLE x)
2595 return MSVCR120_log2(x);
2598 /*********************************************************************
2599 * rint (MSVCR120.@)
2601 double CDECL MSVCR120_rint(double x)
2603 #ifdef HAVE_RINT
2604 return rint(x);
2605 #else
2606 return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5);
2607 #endif
2610 /*********************************************************************
2611 * rintf (MSVCR120.@)
2613 float CDECL MSVCR120_rintf(float x)
2615 #ifdef HAVE_RINTF
2616 return rintf(x);
2617 #else
2618 return MSVCR120_rint(x);
2619 #endif
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)
2635 #ifdef HAVE_LRINT
2636 return lrint(x);
2637 #else
2638 return MSVCR120_rint(x);
2639 #endif
2642 /*********************************************************************
2643 * lrintf (MSVCR120.@)
2645 MSVCRT_long CDECL MSVCR120_lrintf(float x)
2647 #ifdef HAVE_LRINTF
2648 return lrintf(x);
2649 #else
2650 return MSVCR120_lrint(x);
2651 #endif
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)
2667 #ifdef HAVE_LLRINT
2668 return llrint(x);
2669 #else
2670 return MSVCR120_rint(x);
2671 #endif
2674 /*********************************************************************
2675 * llrintf (MSVCR120.@)
2677 MSVCRT_longlong CDECL MSVCR120_llrintf(float x)
2679 #ifdef HAVE_LLRINTF
2680 return llrintf(x);
2681 #else
2682 return MSVCR120_llrint(x);
2683 #endif
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)
2699 #ifdef HAVE_ROUND
2700 return round(x);
2701 #else
2702 return MSVCR120_rint(x);
2703 #endif
2706 /*********************************************************************
2707 * roundf (MSVCR120.@)
2709 float CDECL MSVCR120_roundf(float x)
2711 #ifdef HAVE_ROUNDF
2712 return roundf(x);
2713 #else
2714 return MSVCR120_round(x);
2715 #endif
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)
2731 #ifdef HAVE_LROUND
2732 return lround(x);
2733 #else
2734 return MSVCR120_round(x);
2735 #endif
2738 /*********************************************************************
2739 * lroundf (MSVCR120.@)
2741 MSVCRT_long CDECL MSVCR120_lroundf(float x)
2743 #ifdef HAVE_LROUNDF
2744 return lroundf(x);
2745 #else
2746 return MSVCR120_lround(x);
2747 #endif
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)
2763 #ifdef HAVE_LLROUND
2764 return llround(x);
2765 #else
2766 return MSVCR120_round(x);
2767 #endif
2770 /*********************************************************************
2771 * llroundf (MSVCR120.@)
2773 MSVCRT_longlong CDECL MSVCR120_llroundf(float x)
2775 #ifdef HAVE_LLROUNDF
2776 return llroundf(x);
2777 #else
2778 return MSVCR120_llround(x);
2779 #endif
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)
2795 #ifdef HAVE_TRUNC
2796 return trunc(x);
2797 #else
2798 return (x > 0) ? floor(x) : ceil(x);
2799 #endif
2802 /*********************************************************************
2803 * truncf (MSVCR120.@)
2805 float CDECL MSVCR120_truncf(float x)
2807 #ifdef HAVE_TRUNCF
2808 return truncf(x);
2809 #else
2810 return MSVCR120_trunc(x);
2811 #endif
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:
2839 default:
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 /*********************************************************************
2888 * erf (MSVCR120.@)
2890 double CDECL MSVCR120_erf(double x)
2892 #ifdef HAVE_ERF
2893 return erf(x);
2894 #else
2895 /* Abramowitz and Stegun approximation, maximum error: 1.5*10^-7 */
2896 double t, y;
2897 int sign = signbit(x);
2899 if (sign) x = -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;
2904 #endif
2907 /*********************************************************************
2908 * erff (MSVCR120.@)
2910 float CDECL MSVCR120_erff(float x)
2912 #ifdef HAVE_ERFF
2913 return erff(x);
2914 #else
2915 return MSVCR120_erf(x);
2916 #endif
2919 /*********************************************************************
2920 * erfl (MSVCR120.@)
2922 LDOUBLE CDECL MSVCR120_erfl(LDOUBLE x)
2924 return MSVCR120_erf(x);
2927 /*********************************************************************
2928 * erfc (MSVCR120.@)
2930 double CDECL MSVCR120_erfc(double x)
2932 #ifdef HAVE_ERFC
2933 return erfc(x);
2934 #else
2935 return 1 - MSVCR120_erf(x);
2936 #endif
2939 /*********************************************************************
2940 * erfcf (MSVCR120.@)
2942 float CDECL MSVCR120_erfcf(float x)
2944 #ifdef HAVE_ERFCF
2945 return erfcf(x);
2946 #else
2947 return MSVCR120_erfc(x);
2948 #endif
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)
2964 if(isnanf(x))
2965 return y;
2966 if(isnanf(y))
2967 return x;
2968 if(x==0 && y==0)
2969 return signbit(x) ? y : x;
2970 return x<y ? y : x;
2973 /*********************************************************************
2974 * fmax (MSVCR120.@)
2976 double CDECL MSVCR120_fmax(double x, double y)
2978 if(isnan(x))
2979 return y;
2980 if(isnan(y))
2981 return x;
2982 if(x==0 && y==0)
2983 return signbit(x) ? y : x;
2984 return x<y ? 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))
3010 return 0;
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)
3029 if(isnanf(x))
3030 return y;
3031 if(isnanf(y))
3032 return x;
3033 if(x==0 && y==0)
3034 return signbit(x) ? x : y;
3035 return x<y ? x : y;
3038 /*********************************************************************
3039 * fmin (MSVCR120.@)
3041 double CDECL MSVCR120_fmin(double x, double y)
3043 if(isnan(x))
3044 return y;
3045 if(isnan(y))
3046 return x;
3047 if(x==0 && y==0)
3048 return signbit(x) ? x : y;
3049 return x<y ? x : y;
3052 /*********************************************************************
3053 * asinh (MSVCR120.@)
3055 double CDECL MSVCR120_asinh(double x)
3057 #ifdef HAVE_ASINH
3058 return asinh(x);
3059 #else
3060 if (!isfinite(x*x+1)) return log(2) + log(x);
3061 return log(x + sqrt(x*x+1));
3062 #endif
3065 /*********************************************************************
3066 * asinhf (MSVCR120.@)
3068 float CDECL MSVCR120_asinhf(float x)
3070 #ifdef HAVE_ASINHF
3071 return asinhf(x);
3072 #else
3073 return MSVCR120_asinh(x);
3074 #endif
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;
3092 #ifdef HAVE_ACOSH
3093 return acosh(x);
3094 #else
3095 if (x < 1) {
3096 MSVCRT_fenv_t env;
3098 MSVCRT_fegetenv(&env);
3099 env.status |= MSVCRT__SW_INVALID;
3100 MSVCRT_fesetenv(&env);
3101 return NAN;
3103 if (!isfinite(x*x)) return log(2) + log(x);
3104 return log(x + sqrt(x*x-1));
3105 #endif
3108 /*********************************************************************
3109 * acoshf (MSVCR120.@)
3111 float CDECL MSVCR120_acoshf(float x)
3113 #ifdef HAVE_ACOSHF
3114 if (x < 1) *MSVCRT__errno() = MSVCRT_EDOM;
3116 return acoshf(x);
3117 #else
3118 return MSVCR120_acosh(x);
3119 #endif
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)
3135 double ret;
3137 if (x > 1 || x < -1) {
3138 MSVCRT_fenv_t env;
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);
3146 return NAN;
3149 #ifdef HAVE_ATANH
3150 ret = atanh(x);
3151 #else
3152 if (-1e-6 < x && x < 1e-6) ret = x + x*x*x/3;
3153 else ret = (log(1+x) - log(1-x)) / 2;
3154 #endif
3156 if (!isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
3157 return ret;
3160 /*********************************************************************
3161 * atanhf (MSVCR120.@)
3163 float CDECL MSVCR120_atanhf(float x)
3165 #ifdef HAVE_ATANHF
3166 float ret;
3168 if (x > 1 || x < -1) {
3169 MSVCRT_fenv_t env;
3171 *MSVCRT__errno() = MSVCRT_EDOM;
3173 MSVCRT_fegetenv(&env);
3174 env.status |= MSVCRT__SW_INVALID;
3175 MSVCRT_fesetenv(&env);
3176 return NAN;
3179 ret = atanhf(x);
3181 if (!finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
3182 return ret;
3183 #else
3184 return MSVCR120_atanh(x);
3185 #endif
3188 /*********************************************************************
3189 * atanhl (MSVCR120.@)
3191 LDOUBLE CDECL MSVCR120_atanhl(LDOUBLE x)
3193 return MSVCR120_atanh(x);
3196 /*********************************************************************
3197 * _scalb (MSVCRT.@)
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);
3235 #else
3236 FIXME( "not implemented\n" );
3237 return 0.0;
3238 #endif
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);
3251 #else
3252 FIXME( "not implemented\n" );
3253 return 0.0f;
3254 #endif
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)
3270 #ifdef HAVE_LGAMMA
3271 return lgamma(x);
3272 #else
3273 FIXME( "not implemented\n" );
3274 return 0.0;
3275 #endif
3278 /*********************************************************************
3279 * lgammaf (MSVCR120.@)
3281 float CDECL MSVCR120_lgammaf(float x)
3283 #ifdef HAVE_LGAMMAF
3284 return lgammaf(x);
3285 #else
3286 FIXME( "not implemented\n" );
3287 return 0.0f;
3288 #endif
3291 /*********************************************************************
3292 * lgammal (MSVCR120.@)
3294 LDOUBLE CDECL MSVCR120_lgammal(LDOUBLE x)
3296 return MSVCR120_lgamma(x);
3299 /*********************************************************************
3300 * nan (MSVCR120.@)
3302 double CDECL MSVCR120_nan(const char *tagp)
3304 /* Windows ignores input (MSDN) */
3305 return NAN;
3308 /*********************************************************************
3309 * nanf (MSVCR120.@)
3311 float CDECL MSVCR120_nanf(const char *tagp)
3313 return NAN;
3316 /*********************************************************************
3317 * _except1 (MSVCR120.@)
3318 * TODO:
3319 * - find meaning of ignored cw and operation bits
3320 * - unk parameter
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;
3326 MSVCRT_fenv_t env;
3327 DWORD fpword = 0;
3328 WORD operation;
3330 TRACE("(%x %x %lf %lf %x %p)\n", fpe, op, arg, res, cw, unk);
3332 #ifdef _WIN64
3333 cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
3334 #endif
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;
3346 } else {
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;
3354 } else {
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;
3361 } else {
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;
3367 } else {
3368 exception = EXCEPTION_FLT_INVALID_OPERATION;
3370 } else if (fpe & 0x10) { /* inexact */
3371 if (fpe == 0x10 && (cw & 0x20)) {
3372 env.status |= MSVCRT__SW_INEXACT;
3373 } else {
3374 exception = EXCEPTION_FLT_INEXACT_RESULT;
3378 if (exception)
3379 env.status = 0;
3380 MSVCRT_fesetenv(&env);
3381 if (exception)
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;
3390 switch (cw & 0xc00)
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;
3396 switch (cw & 0x300)
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);
3405 return res;