wineconsole: Try harder to get a scalable font.
[wine.git] / dlls / msvcrt / math.c
blobd4785d3508535d762ce81dfda320356638e14ca1
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 /* FIXME: Does not work with -NAN and -0. */
42 #ifndef signbit
43 #define signbit(x) ((x) < 0)
44 #endif
46 #define _DOMAIN 1 /* domain error in argument */
47 #define _SING 2 /* singularity */
48 #define _OVERFLOW 3 /* range overflow */
49 #define _UNDERFLOW 4 /* range underflow */
51 typedef int (CDECL *MSVCRT_matherr_func)(struct MSVCRT__exception *);
52 typedef double LDOUBLE; /* long double is just a double */
54 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
56 static BOOL sse2_supported;
57 static BOOL sse2_enabled;
59 void msvcrt_init_math(void)
61 sse2_supported = sse2_enabled = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
64 /*********************************************************************
65 * _matherr (MSVCRT.@)
67 int CDECL MSVCRT__matherr(struct MSVCRT__exception *e)
69 int ret;
71 if (e)
72 TRACE("(%p = {%d, \"%s\", %g, %g, %g})\n", e, e->type, e->name, e->arg1, e->arg2, e->retval);
73 else
74 TRACE("(null)\n");
76 if (MSVCRT_default_matherr_func)
78 ret = MSVCRT_default_matherr_func(e);
79 if (ret) return ret;
82 switch (e->type)
84 case _DOMAIN:
85 *MSVCRT__errno() = MSVCRT_EDOM;
86 break;
87 case _SING:
88 case _OVERFLOW:
89 *MSVCRT__errno() = MSVCRT_ERANGE;
90 break;
91 case _UNDERFLOW:
92 /* don't set errno */
93 break;
94 default:
95 ERR("Unhandled math error!\n");
98 return 0;
101 /*********************************************************************
102 * __setusermatherr (MSVCRT.@)
104 void CDECL MSVCRT___setusermatherr(MSVCRT_matherr_func func)
106 MSVCRT_default_matherr_func = func;
107 TRACE("new matherr handler %p\n", func);
110 static inline void math_error(int type, const char *name, double arg1, double arg2, double retval)
112 struct MSVCRT__exception exception = {type, (char *)name, arg1, arg2, retval};
113 MSVCRT__matherr(&exception);
116 /*********************************************************************
117 * _set_SSE2_enable (MSVCRT.@)
119 int CDECL MSVCRT__set_SSE2_enable(int flag)
121 sse2_enabled = flag && sse2_supported;
122 return sse2_enabled;
125 #if defined(_WIN64) && _MSVCR_VER>=120
126 /*********************************************************************
127 * _set_FMA3_enable (MSVCR120.@)
129 int CDECL MSVCRT__set_FMA3_enable(int flag)
131 FIXME("(%x) stub\n", flag);
132 return 0;
134 #endif
136 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || _MSVCR_VER>=120
138 /*********************************************************************
139 * _chgsignf (MSVCRT.@)
141 float CDECL MSVCRT__chgsignf( float num )
143 /* FIXME: +-infinity,Nan not tested */
144 return -num;
147 /*********************************************************************
148 * _copysignf (MSVCRT.@)
150 float CDECL MSVCRT__copysignf( float num, float sign )
152 if (signbit(sign))
153 return signbit(num) ? num : -num;
154 return signbit(num) ? -num : num;
157 /*********************************************************************
158 * _nextafterf (MSVCRT.@)
160 float CDECL MSVCRT__nextafterf( float num, float next )
162 if (!finitef(num) || !finitef(next)) *MSVCRT__errno() = MSVCRT_EDOM;
163 return nextafterf( num, next );
166 #endif
167 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
169 /*********************************************************************
170 * _finitef (MSVCRT.@)
172 int CDECL MSVCRT__finitef( float num )
174 return finitef(num) != 0; /* See comment for _isnan() */
177 /*********************************************************************
178 * _isnanf (MSVCRT.@)
180 INT CDECL MSVCRT__isnanf( float num )
182 /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
183 * Do the same, as the result may be used in calculations
185 return isnan(num) != 0;
188 /*********************************************************************
189 * _logbf (MSVCRT.@)
191 float CDECL MSVCRT__logbf( float num )
193 float ret = logbf(num);
194 if (isnan(num)) math_error(_DOMAIN, "_logbf", num, 0, ret);
195 else if (!num) math_error(_SING, "_logbf", num, 0, ret);
196 return ret;
199 /*********************************************************************
200 * MSVCRT_acosf (MSVCRT.@)
202 float CDECL MSVCRT_acosf( float x )
204 /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
205 * asin() uses a similar construction. This is bad because as x gets nearer to
206 * 1 the error in the expression "1 - x^2" can get relatively large due to
207 * cancellation. The sqrt() makes things worse. A safer way to calculate
208 * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
209 float ret = atan2f(sqrtf((1 - x) * (1 + x)), x);
210 if (x < -1.0 || x > 1.0 || !finitef(x)) math_error(_DOMAIN, "acosf", x, 0, ret);
211 return ret;
214 /*********************************************************************
215 * MSVCRT_asinf (MSVCRT.@)
217 float CDECL MSVCRT_asinf( float x )
219 float ret = atan2f(x, sqrtf((1 - x) * (1 + x)));
220 if (x < -1.0 || x > 1.0 || !finitef(x)) math_error(_DOMAIN, "asinf", x, 0, ret);
221 return ret;
224 /*********************************************************************
225 * MSVCRT_atanf (MSVCRT.@)
227 float CDECL MSVCRT_atanf( float x )
229 float ret = atanf(x);
230 if (!finitef(x)) math_error(_DOMAIN, "atanf", x, 0, ret);
231 return ret;
234 /*********************************************************************
235 * MSVCRT_atan2f (MSVCRT.@)
237 float CDECL MSVCRT_atan2f( float x, float y )
239 float ret = atan2f(x, y);
240 if (isnan(x)) math_error(_DOMAIN, "atan2f", x, y, ret);
241 return ret;
244 /*********************************************************************
245 * MSVCRT_cosf (MSVCRT.@)
247 float CDECL MSVCRT_cosf( float x )
249 float ret = cosf(x);
250 if (!finitef(x)) math_error(_DOMAIN, "cosf", x, 0, ret);
251 return ret;
254 /*********************************************************************
255 * MSVCRT_coshf (MSVCRT.@)
257 float CDECL MSVCRT_coshf( float x )
259 float ret = coshf(x);
260 if (isnan(x)) math_error(_DOMAIN, "coshf", x, 0, ret);
261 return ret;
264 /*********************************************************************
265 * MSVCRT_expf (MSVCRT.@)
267 float CDECL MSVCRT_expf( float x )
269 float ret = expf(x);
270 if (isnan(x)) math_error(_DOMAIN, "expf", x, 0, ret);
271 else if (finitef(x) && !ret) math_error(_UNDERFLOW, "expf", x, 0, ret);
272 else if (finitef(x) && !finitef(ret)) math_error(_OVERFLOW, "expf", x, 0, ret);
273 return ret;
276 /*********************************************************************
277 * MSVCRT_fmodf (MSVCRT.@)
279 float CDECL MSVCRT_fmodf( float x, float y )
281 float ret = fmodf(x, y);
282 if (!finitef(x) || !finitef(y)) math_error(_DOMAIN, "fmodf", x, 0, ret);
283 return ret;
286 /*********************************************************************
287 * MSVCRT_logf (MSVCRT.@)
289 float CDECL MSVCRT_logf( float x )
291 float ret = logf(x);
292 if (x < 0.0) math_error(_DOMAIN, "logf", x, 0, ret);
293 else if (x == 0.0) math_error(_SING, "logf", x, 0, ret);
294 return ret;
297 /*********************************************************************
298 * MSVCRT_log10f (MSVCRT.@)
300 float CDECL MSVCRT_log10f( float x )
302 float ret = log10f(x);
303 if (x < 0.0) math_error(_DOMAIN, "log10f", x, 0, ret);
304 else if (x == 0.0) math_error(_SING, "log10f", x, 0, ret);
305 return ret;
308 /*********************************************************************
309 * MSVCRT_powf (MSVCRT.@)
311 float CDECL MSVCRT_powf( float x, float y )
313 float z = powf(x,y);
314 if (x < 0 && y != floorf(y)) math_error(_DOMAIN, "powf", x, y, z);
315 else if (!x && finitef(y) && y < 0) math_error(_SING, "powf", x, y, z);
316 else if (finitef(x) && finitef(y) && !finitef(z)) math_error(_OVERFLOW, "powf", x, y, z);
317 else if (x && finitef(x) && finitef(y) && !z) math_error(_UNDERFLOW, "powf", x, y, z);
318 return z;
321 /*********************************************************************
322 * MSVCRT_sinf (MSVCRT.@)
324 float CDECL MSVCRT_sinf( float x )
326 float ret = sinf(x);
327 if (!finitef(x)) math_error(_DOMAIN, "sinf", x, 0, ret);
328 return ret;
331 /*********************************************************************
332 * MSVCRT_sinhf (MSVCRT.@)
334 float CDECL MSVCRT_sinhf( float x )
336 float ret = sinhf(x);
337 if (isnan(x)) math_error(_DOMAIN, "sinhf", x, 0, ret);
338 return ret;
341 /*********************************************************************
342 * MSVCRT_sqrtf (MSVCRT.@)
344 float CDECL MSVCRT_sqrtf( float x )
346 float ret = sqrtf(x);
347 if (x < 0.0) math_error(_DOMAIN, "sqrtf", x, 0, ret);
348 return ret;
351 /*********************************************************************
352 * MSVCRT_tanf (MSVCRT.@)
354 float CDECL MSVCRT_tanf( float x )
356 float ret = tanf(x);
357 if (!finitef(x)) math_error(_DOMAIN, "tanf", x, 0, ret);
358 return ret;
361 /*********************************************************************
362 * MSVCRT_tanhf (MSVCRT.@)
364 float CDECL MSVCRT_tanhf( float x )
366 float ret = tanhf(x);
367 if (!finitef(x)) math_error(_DOMAIN, "tanhf", x, 0, ret);
368 return ret;
371 /*********************************************************************
372 * ceilf (MSVCRT.@)
374 float CDECL MSVCRT_ceilf( float x )
376 return ceilf(x);
379 /*********************************************************************
380 * fabsf (MSVCRT.@)
382 float CDECL MSVCRT_fabsf( float x )
384 return fabsf(x);
387 /*********************************************************************
388 * floorf (MSVCRT.@)
390 float CDECL MSVCRT_floorf( float x )
392 return floorf(x);
395 /*********************************************************************
396 * frexpf (MSVCRT.@)
398 float CDECL MSVCRT_frexpf( float x, int *exp )
400 return frexpf( x, exp );
403 /*********************************************************************
404 * modff (MSVCRT.@)
406 float CDECL MSVCRT_modff( float x, float *iptr )
408 return modff( x, iptr );
411 #endif
413 /*********************************************************************
414 * MSVCRT_acos (MSVCRT.@)
416 double CDECL MSVCRT_acos( double x )
418 /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
419 * asin() uses a similar construction. This is bad because as x gets nearer to
420 * 1 the error in the expression "1 - x^2" can get relatively large due to
421 * cancellation. The sqrt() makes things worse. A safer way to calculate
422 * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
423 double ret = atan2(sqrt((1 - x) * (1 + x)), x);
424 if (x < -1.0 || x > 1.0 || !isfinite(x)) math_error(_DOMAIN, "acos", x, 0, ret);
425 return ret;
428 /*********************************************************************
429 * MSVCRT_asin (MSVCRT.@)
431 double CDECL MSVCRT_asin( double x )
433 double ret = atan2(x, sqrt((1 - x) * (1 + x)));
434 if (x < -1.0 || x > 1.0 || !isfinite(x)) math_error(_DOMAIN, "asin", x, 0, ret);
435 return ret;
438 /*********************************************************************
439 * MSVCRT_atan (MSVCRT.@)
441 double CDECL MSVCRT_atan( double x )
443 double ret = atan(x);
444 if (isnan(x)) math_error(_DOMAIN, "atan", x, 0, ret);
445 return ret;
448 /*********************************************************************
449 * MSVCRT_atan2 (MSVCRT.@)
451 double CDECL MSVCRT_atan2( double x, double y )
453 double ret = atan2(x, y);
454 if (isnan(x)) math_error(_DOMAIN, "atan2", x, y, ret);
455 return ret;
458 /*********************************************************************
459 * MSVCRT_cos (MSVCRT.@)
461 double CDECL MSVCRT_cos( double x )
463 double ret = cos(x);
464 if (!isfinite(x)) math_error(_DOMAIN, "cos", x, 0, ret);
465 return ret;
468 /*********************************************************************
469 * MSVCRT_cosh (MSVCRT.@)
471 double CDECL MSVCRT_cosh( double x )
473 double ret = cosh(x);
474 if (isnan(x)) math_error(_DOMAIN, "cosh", x, 0, ret);
475 return ret;
478 /*********************************************************************
479 * MSVCRT_exp (MSVCRT.@)
481 double CDECL MSVCRT_exp( double x )
483 double ret = exp(x);
484 if (isnan(x)) math_error(_DOMAIN, "exp", x, 0, ret);
485 else if (isfinite(x) && !ret) math_error(_UNDERFLOW, "exp", x, 0, ret);
486 else if (isfinite(x) && !isfinite(ret)) math_error(_OVERFLOW, "exp", x, 0, ret);
487 return ret;
490 /*********************************************************************
491 * MSVCRT_fmod (MSVCRT.@)
493 double CDECL MSVCRT_fmod( double x, double y )
495 double ret = fmod(x, y);
496 if (!isfinite(x) || !isfinite(y)) math_error(_DOMAIN, "fmod", x, y, ret);
497 return ret;
500 /*********************************************************************
501 * MSVCRT_log (MSVCRT.@)
503 double CDECL MSVCRT_log( double x )
505 double ret = log(x);
506 if (x < 0.0) math_error(_DOMAIN, "log", x, 0, ret);
507 else if (x == 0.0) math_error(_SING, "log", x, 0, ret);
508 return ret;
511 /*********************************************************************
512 * MSVCRT_log10 (MSVCRT.@)
514 double CDECL MSVCRT_log10( double x )
516 double ret = log10(x);
517 if (x < 0.0) math_error(_DOMAIN, "log10", x, 0, ret);
518 else if (x == 0.0) math_error(_SING, "log10", x, 0, ret);
519 return ret;
522 /*********************************************************************
523 * MSVCRT_pow (MSVCRT.@)
525 double CDECL MSVCRT_pow( double x, double y )
527 double z = pow(x,y);
528 if (x < 0 && y != floor(y)) math_error(_DOMAIN, "pow", x, y, z);
529 else if (!x && isfinite(y) && y < 0) math_error(_SING, "pow", x, y, z);
530 else if (isfinite(x) && isfinite(y) && !isfinite(z)) math_error(_OVERFLOW, "pow", x, y, z);
531 else if (x && isfinite(x) && isfinite(y) && !z) math_error(_UNDERFLOW, "pow", x, y, z);
532 return z;
535 /*********************************************************************
536 * MSVCRT_sin (MSVCRT.@)
538 double CDECL MSVCRT_sin( double x )
540 double ret = sin(x);
541 if (!isfinite(x)) math_error(_DOMAIN, "sin", x, 0, ret);
542 return ret;
545 /*********************************************************************
546 * MSVCRT_sinh (MSVCRT.@)
548 double CDECL MSVCRT_sinh( double x )
550 double ret = sinh(x);
551 if (isnan(x)) math_error(_DOMAIN, "sinh", x, 0, ret);
552 return ret;
555 /*********************************************************************
556 * MSVCRT_sqrt (MSVCRT.@)
558 double CDECL MSVCRT_sqrt( double x )
560 double ret = sqrt(x);
561 if (x < 0.0) math_error(_DOMAIN, "sqrt", x, 0, ret);
562 return ret;
565 /*********************************************************************
566 * MSVCRT_tan (MSVCRT.@)
568 double CDECL MSVCRT_tan( double x )
570 double ret = tan(x);
571 if (!isfinite(x)) math_error(_DOMAIN, "tan", x, 0, ret);
572 return ret;
575 /*********************************************************************
576 * MSVCRT_tanh (MSVCRT.@)
578 double CDECL MSVCRT_tanh( double x )
580 double ret = tanh(x);
581 if (isnan(x)) math_error(_DOMAIN, "tanh", x, 0, ret);
582 return ret;
586 #if defined(__GNUC__) && defined(__i386__)
588 #define CREATE_FPU_FUNC1(name, call) \
589 __ASM_GLOBAL_FUNC(name, \
590 "pushl %ebp\n\t" \
591 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
592 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
593 "movl %esp, %ebp\n\t" \
594 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
595 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
596 "fstpl (%esp)\n\t" /* store function argument */ \
597 "fwait\n\t" \
598 "movl $1, %ecx\n\t" /* empty FPU stack */ \
599 "1:\n\t" \
600 "fxam\n\t" \
601 "fstsw %ax\n\t" \
602 "and $0x4500, %ax\n\t" \
603 "cmp $0x4100, %ax\n\t" \
604 "je 2f\n\t" \
605 "fstpl (%esp,%ecx,8)\n\t" \
606 "fwait\n\t" \
607 "incl %ecx\n\t" \
608 "jmp 1b\n\t" \
609 "2:\n\t" \
610 "movl %ecx, -4(%ebp)\n\t" \
611 "call " __ASM_NAME( #call ) "\n\t" \
612 "movl -4(%ebp), %ecx\n\t" \
613 "fstpl (%esp)\n\t" /* save result */ \
614 "3:\n\t" /* restore FPU stack */ \
615 "decl %ecx\n\t" \
616 "fldl (%esp,%ecx,8)\n\t" \
617 "cmpl $0, %ecx\n\t" \
618 "jne 3b\n\t" \
619 "leave\n\t" \
620 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
621 __ASM_CFI(".cfi_same_value %ebp\n\t") \
622 "ret")
624 #define CREATE_FPU_FUNC2(name, call) \
625 __ASM_GLOBAL_FUNC(name, \
626 "pushl %ebp\n\t" \
627 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
628 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
629 "movl %esp, %ebp\n\t" \
630 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
631 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
632 "fstpl 8(%esp)\n\t" /* store function argument */ \
633 "fwait\n\t" \
634 "fstpl (%esp)\n\t" \
635 "fwait\n\t" \
636 "movl $2, %ecx\n\t" /* empty FPU stack */ \
637 "1:\n\t" \
638 "fxam\n\t" \
639 "fstsw %ax\n\t" \
640 "and $0x4500, %ax\n\t" \
641 "cmp $0x4100, %ax\n\t" \
642 "je 2f\n\t" \
643 "fstpl (%esp,%ecx,8)\n\t" \
644 "fwait\n\t" \
645 "incl %ecx\n\t" \
646 "jmp 1b\n\t" \
647 "2:\n\t" \
648 "movl %ecx, -4(%ebp)\n\t" \
649 "call " __ASM_NAME( #call ) "\n\t" \
650 "movl -4(%ebp), %ecx\n\t" \
651 "fstpl 8(%esp)\n\t" /* save result */ \
652 "3:\n\t" /* restore FPU stack */ \
653 "decl %ecx\n\t" \
654 "fldl (%esp,%ecx,8)\n\t" \
655 "cmpl $1, %ecx\n\t" \
656 "jne 3b\n\t" \
657 "leave\n\t" \
658 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
659 __ASM_CFI(".cfi_same_value %ebp\n\t") \
660 "ret")
662 CREATE_FPU_FUNC1(_CIacos, MSVCRT_acos)
663 CREATE_FPU_FUNC1(_CIasin, MSVCRT_asin)
664 CREATE_FPU_FUNC1(_CIatan, MSVCRT_atan)
665 CREATE_FPU_FUNC2(_CIatan2, MSVCRT_atan2)
666 CREATE_FPU_FUNC1(_CIcos, MSVCRT_cos)
667 CREATE_FPU_FUNC1(_CIcosh, MSVCRT_cosh)
668 CREATE_FPU_FUNC1(_CIexp, MSVCRT_exp)
669 CREATE_FPU_FUNC2(_CIfmod, MSVCRT_fmod)
670 CREATE_FPU_FUNC1(_CIlog, MSVCRT_log)
671 CREATE_FPU_FUNC1(_CIlog10, MSVCRT_log10)
672 CREATE_FPU_FUNC2(_CIpow, MSVCRT_pow)
673 CREATE_FPU_FUNC1(_CIsin, MSVCRT_sin)
674 CREATE_FPU_FUNC1(_CIsinh, MSVCRT_sinh)
675 CREATE_FPU_FUNC1(_CIsqrt, MSVCRT_sqrt)
676 CREATE_FPU_FUNC1(_CItan, MSVCRT_tan)
677 CREATE_FPU_FUNC1(_CItanh, MSVCRT_tanh)
679 __ASM_GLOBAL_FUNC(MSVCRT__ftol,
680 "pushl %ebp\n\t"
681 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
682 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
683 "movl %esp, %ebp\n\t"
684 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
685 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
686 "fnstcw (%esp)\n\t"
687 "mov (%esp), %ax\n\t"
688 "or $0xc00, %ax\n\t"
689 "mov %ax, 2(%esp)\n\t"
690 "fldcw 2(%esp)\n\t"
691 "fistpq 4(%esp)\n\t"
692 "fldcw (%esp)\n\t"
693 "movl 4(%esp), %eax\n\t"
694 "movl 8(%esp), %edx\n\t"
695 "leave\n\t"
696 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
697 __ASM_CFI(".cfi_same_value %ebp\n\t")
698 "ret")
700 #endif /* defined(__GNUC__) && defined(__i386__) */
702 /*********************************************************************
703 * _fpclass (MSVCRT.@)
705 int CDECL MSVCRT__fpclass(double num)
707 #if defined(HAVE_FPCLASS) || defined(fpclass)
708 switch (fpclass( num ))
710 case FP_SNAN: return MSVCRT__FPCLASS_SNAN;
711 case FP_QNAN: return MSVCRT__FPCLASS_QNAN;
712 case FP_NINF: return MSVCRT__FPCLASS_NINF;
713 case FP_PINF: return MSVCRT__FPCLASS_PINF;
714 case FP_NDENORM: return MSVCRT__FPCLASS_ND;
715 case FP_PDENORM: return MSVCRT__FPCLASS_PD;
716 case FP_NZERO: return MSVCRT__FPCLASS_NZ;
717 case FP_PZERO: return MSVCRT__FPCLASS_PZ;
718 case FP_NNORM: return MSVCRT__FPCLASS_NN;
719 case FP_PNORM: return MSVCRT__FPCLASS_PN;
720 default: return MSVCRT__FPCLASS_PN;
722 #elif defined (fpclassify)
723 switch (fpclassify( num ))
725 case FP_NAN: return MSVCRT__FPCLASS_QNAN;
726 case FP_INFINITE: return signbit(num) ? MSVCRT__FPCLASS_NINF : MSVCRT__FPCLASS_PINF;
727 case FP_SUBNORMAL: return signbit(num) ?MSVCRT__FPCLASS_ND : MSVCRT__FPCLASS_PD;
728 case FP_ZERO: return signbit(num) ? MSVCRT__FPCLASS_NZ : MSVCRT__FPCLASS_PZ;
730 return signbit(num) ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN;
731 #else
732 if (!isfinite(num))
733 return MSVCRT__FPCLASS_QNAN;
734 return num == 0.0 ? MSVCRT__FPCLASS_PZ : (num < 0 ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN);
735 #endif
738 /*********************************************************************
739 * _rotl (MSVCRT.@)
741 unsigned int CDECL _rotl(unsigned int num, int shift)
743 shift &= 31;
744 return (num << shift) | (num >> (32-shift));
747 /*********************************************************************
748 * _lrotl (MSVCRT.@)
750 MSVCRT_ulong CDECL MSVCRT__lrotl(MSVCRT_ulong num, int shift)
752 shift &= 0x1f;
753 return (num << shift) | (num >> (32-shift));
756 /*********************************************************************
757 * _lrotr (MSVCRT.@)
759 MSVCRT_ulong CDECL MSVCRT__lrotr(MSVCRT_ulong num, int shift)
761 shift &= 0x1f;
762 return (num >> shift) | (num << (32-shift));
765 /*********************************************************************
766 * _rotr (MSVCRT.@)
768 unsigned int CDECL _rotr(unsigned int num, int shift)
770 shift &= 0x1f;
771 return (num >> shift) | (num << (32-shift));
774 /*********************************************************************
775 * _rotl64 (MSVCRT.@)
777 unsigned __int64 CDECL _rotl64(unsigned __int64 num, int shift)
779 shift &= 63;
780 return (num << shift) | (num >> (64-shift));
783 /*********************************************************************
784 * _rotr64 (MSVCRT.@)
786 unsigned __int64 CDECL _rotr64(unsigned __int64 num, int shift)
788 shift &= 63;
789 return (num >> shift) | (num << (64-shift));
792 /*********************************************************************
793 * abs (MSVCRT.@)
795 int CDECL MSVCRT_abs( int n )
797 return n >= 0 ? n : -n;
800 /*********************************************************************
801 * labs (MSVCRT.@)
803 MSVCRT_long CDECL MSVCRT_labs( MSVCRT_long n )
805 return n >= 0 ? n : -n;
808 #if _MSVCR_VER>=100
809 /*********************************************************************
810 * llabs (MSVCR100.@)
812 MSVCRT_longlong CDECL MSVCRT_llabs( MSVCRT_longlong n )
814 return n >= 0 ? n : -n;
816 #endif
818 /*********************************************************************
819 * _abs64 (MSVCRT.@)
821 __int64 CDECL _abs64( __int64 n )
823 return n >= 0 ? n : -n;
826 /*********************************************************************
827 * _logb (MSVCRT.@)
829 double CDECL MSVCRT__logb(double num)
831 double ret = logb(num);
832 if (isnan(num)) math_error(_DOMAIN, "_logb", num, 0, ret);
833 else if (!num) math_error(_SING, "_logb", num, 0, ret);
834 return ret;
837 /*********************************************************************
838 * _hypot (MSVCRT.@)
840 double CDECL _hypot(double x, double y)
842 /* FIXME: errno handling */
843 return hypot( x, y );
846 /*********************************************************************
847 * _hypotf (MSVCRT.@)
849 float CDECL MSVCRT__hypotf(float x, float y)
851 /* FIXME: errno handling */
852 return hypotf( x, y );
855 /*********************************************************************
856 * ceil (MSVCRT.@)
858 double CDECL MSVCRT_ceil( double x )
860 return ceil(x);
863 /*********************************************************************
864 * floor (MSVCRT.@)
866 double CDECL MSVCRT_floor( double x )
868 return floor(x);
871 /*********************************************************************
872 * fabs (MSVCRT.@)
874 double CDECL MSVCRT_fabs( double x )
876 return fabs(x);
879 /*********************************************************************
880 * frexp (MSVCRT.@)
882 double CDECL MSVCRT_frexp( double x, int *exp )
884 return frexp( x, exp );
887 /*********************************************************************
888 * modf (MSVCRT.@)
890 double CDECL MSVCRT_modf( double x, double *iptr )
892 return modf( x, iptr );
895 /**********************************************************************
896 * _statusfp2 (MSVCRT.@)
898 * Not exported by native msvcrt, added in msvcr80.
900 #if defined(__i386__) || defined(__x86_64__)
901 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
903 #ifdef __GNUC__
904 unsigned int flags;
905 unsigned long fpword;
907 if (x86_sw)
909 __asm__ __volatile__( "fstsw %0" : "=m" (fpword) );
910 flags = 0;
911 if (fpword & 0x1) flags |= MSVCRT__SW_INVALID;
912 if (fpword & 0x2) flags |= MSVCRT__SW_DENORMAL;
913 if (fpword & 0x4) flags |= MSVCRT__SW_ZERODIVIDE;
914 if (fpword & 0x8) flags |= MSVCRT__SW_OVERFLOW;
915 if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
916 if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
917 *x86_sw = flags;
920 if (!sse2_sw) return;
922 if (sse2_supported)
924 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
925 flags = 0;
926 if (fpword & 0x1) flags |= MSVCRT__SW_INVALID;
927 if (fpword & 0x2) flags |= MSVCRT__SW_DENORMAL;
928 if (fpword & 0x4) flags |= MSVCRT__SW_ZERODIVIDE;
929 if (fpword & 0x8) flags |= MSVCRT__SW_OVERFLOW;
930 if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
931 if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
932 *sse2_sw = flags;
934 else *sse2_sw = 0;
935 #else
936 FIXME( "not implemented\n" );
937 #endif
939 #endif
941 /**********************************************************************
942 * _statusfp (MSVCRT.@)
944 unsigned int CDECL _statusfp(void)
946 #if defined(__i386__) || defined(__x86_64__)
947 unsigned int x86_sw, sse2_sw;
949 _statusfp2( &x86_sw, &sse2_sw );
950 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
951 return x86_sw | sse2_sw;
952 #else
953 FIXME( "not implemented\n" );
954 return 0;
955 #endif
958 /*********************************************************************
959 * _clearfp (MSVCRT.@)
961 unsigned int CDECL _clearfp(void)
963 unsigned int flags = 0;
964 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
965 unsigned long fpword;
967 __asm__ __volatile__( "fnstsw %0; fnclex" : "=m" (fpword) );
968 if (fpword & 0x1) flags |= MSVCRT__SW_INVALID;
969 if (fpword & 0x2) flags |= MSVCRT__SW_DENORMAL;
970 if (fpword & 0x4) flags |= MSVCRT__SW_ZERODIVIDE;
971 if (fpword & 0x8) flags |= MSVCRT__SW_OVERFLOW;
972 if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
973 if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
975 if (sse2_supported)
977 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
978 if (fpword & 0x1) flags |= MSVCRT__SW_INVALID;
979 if (fpword & 0x2) flags |= MSVCRT__SW_DENORMAL;
980 if (fpword & 0x4) flags |= MSVCRT__SW_ZERODIVIDE;
981 if (fpword & 0x8) flags |= MSVCRT__SW_OVERFLOW;
982 if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
983 if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
984 fpword &= ~0x3f;
985 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
987 #else
988 FIXME( "not implemented\n" );
989 #endif
990 return flags;
993 /*********************************************************************
994 * __fpecode (MSVCRT.@)
996 int * CDECL __fpecode(void)
998 return &msvcrt_get_thread_data()->fpecode;
1001 /*********************************************************************
1002 * ldexp (MSVCRT.@)
1004 double CDECL MSVCRT_ldexp(double num, MSVCRT_long exp)
1006 double z = ldexp(num,exp);
1008 if (isfinite(num) && !isfinite(z))
1009 math_error(_OVERFLOW, "ldexp", num, exp, z);
1010 else if (num && isfinite(num) && !z)
1011 math_error(_UNDERFLOW, "ldexp", num, exp, z);
1012 else if (z == 0 && signbit(z))
1013 z = 0.0; /* Convert -0 -> +0 */
1014 return z;
1017 /*********************************************************************
1018 * _cabs (MSVCRT.@)
1020 double CDECL MSVCRT__cabs(struct MSVCRT__complex num)
1022 return sqrt(num.x * num.x + num.y * num.y);
1025 /*********************************************************************
1026 * _chgsign (MSVCRT.@)
1028 double CDECL MSVCRT__chgsign(double num)
1030 /* FIXME: +-infinity,Nan not tested */
1031 return -num;
1034 /*********************************************************************
1035 * __control87_2 (MSVCR80.@)
1037 * Not exported by native msvcrt, added in msvcr80.
1039 #if defined(__i386__) || defined(__x86_64__)
1040 int CDECL __control87_2( unsigned int newval, unsigned int mask,
1041 unsigned int *x86_cw, unsigned int *sse2_cw )
1043 #ifdef __GNUC__
1044 unsigned long fpword;
1045 unsigned int flags;
1047 if (x86_cw)
1049 __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
1051 /* Convert into mask constants */
1052 flags = 0;
1053 if (fpword & 0x1) flags |= MSVCRT__EM_INVALID;
1054 if (fpword & 0x2) flags |= MSVCRT__EM_DENORMAL;
1055 if (fpword & 0x4) flags |= MSVCRT__EM_ZERODIVIDE;
1056 if (fpword & 0x8) flags |= MSVCRT__EM_OVERFLOW;
1057 if (fpword & 0x10) flags |= MSVCRT__EM_UNDERFLOW;
1058 if (fpword & 0x20) flags |= MSVCRT__EM_INEXACT;
1059 switch (fpword & 0xc00)
1061 case 0xc00: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
1062 case 0x800: flags |= MSVCRT__RC_UP; break;
1063 case 0x400: flags |= MSVCRT__RC_DOWN; break;
1065 switch (fpword & 0x300)
1067 case 0x0: flags |= MSVCRT__PC_24; break;
1068 case 0x200: flags |= MSVCRT__PC_53; break;
1069 case 0x300: flags |= MSVCRT__PC_64; break;
1071 if (fpword & 0x1000) flags |= MSVCRT__IC_AFFINE;
1073 TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1074 if (mask)
1076 flags = (flags & ~mask) | (newval & mask);
1078 /* Convert (masked) value back to fp word */
1079 fpword = 0;
1080 if (flags & MSVCRT__EM_INVALID) fpword |= 0x1;
1081 if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x2;
1082 if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x4;
1083 if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x8;
1084 if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x10;
1085 if (flags & MSVCRT__EM_INEXACT) fpword |= 0x20;
1086 switch (flags & MSVCRT__MCW_RC)
1088 case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0xc00; break;
1089 case MSVCRT__RC_UP: fpword |= 0x800; break;
1090 case MSVCRT__RC_DOWN: fpword |= 0x400; break;
1092 switch (flags & MSVCRT__MCW_PC)
1094 case MSVCRT__PC_64: fpword |= 0x300; break;
1095 case MSVCRT__PC_53: fpword |= 0x200; break;
1096 case MSVCRT__PC_24: fpword |= 0x0; break;
1098 if (flags & MSVCRT__IC_AFFINE) fpword |= 0x1000;
1100 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1102 *x86_cw = flags;
1105 if (!sse2_cw) return 1;
1107 if (sse2_supported)
1109 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1111 /* Convert into mask constants */
1112 flags = 0;
1113 if (fpword & 0x80) flags |= MSVCRT__EM_INVALID;
1114 if (fpword & 0x100) flags |= MSVCRT__EM_DENORMAL;
1115 if (fpword & 0x200) flags |= MSVCRT__EM_ZERODIVIDE;
1116 if (fpword & 0x400) flags |= MSVCRT__EM_OVERFLOW;
1117 if (fpword & 0x800) flags |= MSVCRT__EM_UNDERFLOW;
1118 if (fpword & 0x1000) flags |= MSVCRT__EM_INEXACT;
1119 switch (fpword & 0x6000)
1121 case 0x6000: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
1122 case 0x4000: flags |= MSVCRT__RC_UP; break;
1123 case 0x2000: flags |= MSVCRT__RC_DOWN; break;
1125 switch (fpword & 0x8040)
1127 case 0x0040: flags |= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1128 case 0x8000: flags |= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1129 case 0x8040: flags |= MSVCRT__DN_FLUSH; break;
1132 TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1133 if (mask)
1135 flags = (flags & ~mask) | (newval & mask);
1137 /* Convert (masked) value back to fp word */
1138 fpword = 0;
1139 if (flags & MSVCRT__EM_INVALID) fpword |= 0x80;
1140 if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x100;
1141 if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
1142 if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
1143 if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
1144 if (flags & MSVCRT__EM_INEXACT) fpword |= 0x1000;
1145 switch (flags & MSVCRT__MCW_RC)
1147 case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0x6000; break;
1148 case MSVCRT__RC_UP: fpword |= 0x4000; break;
1149 case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
1151 switch (flags & MSVCRT__MCW_DN)
1153 case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1154 case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1155 case MSVCRT__DN_FLUSH: fpword |= 0x8040; break;
1157 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1159 *sse2_cw = flags;
1161 else *sse2_cw = 0;
1163 return 1;
1164 #else
1165 FIXME( "not implemented\n" );
1166 return 0;
1167 #endif
1169 #endif
1171 /*********************************************************************
1172 * _control87 (MSVCRT.@)
1174 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1176 #if defined(__i386__) || defined(__x86_64__)
1177 unsigned int x86_cw, sse2_cw;
1179 __control87_2( newval, mask, &x86_cw, &sse2_cw );
1181 if ((x86_cw ^ sse2_cw) & (MSVCRT__MCW_EM | MSVCRT__MCW_RC)) x86_cw |= MSVCRT__EM_AMBIGUOUS;
1182 return x86_cw;
1183 #else
1184 FIXME( "not implemented\n" );
1185 return 0;
1186 #endif
1189 /*********************************************************************
1190 * _controlfp (MSVCRT.@)
1192 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
1194 return _control87( newval, mask & ~MSVCRT__EM_DENORMAL );
1197 /*********************************************************************
1198 * _set_controlfp (MSVCRT.@)
1200 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
1202 _controlfp( newval, mask );
1205 /*********************************************************************
1206 * _controlfp_s (MSVCRT.@)
1208 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
1210 static const unsigned int all_flags = (MSVCRT__MCW_EM | MSVCRT__MCW_IC | MSVCRT__MCW_RC |
1211 MSVCRT__MCW_PC | MSVCRT__MCW_DN);
1212 unsigned int val;
1214 if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
1216 if (cur) *cur = _controlfp( 0, 0 ); /* retrieve it anyway */
1217 return MSVCRT_EINVAL;
1219 val = _controlfp( newval, mask );
1220 if (cur) *cur = val;
1221 return 0;
1224 #if _MSVCR_VER>=120
1225 /*********************************************************************
1226 * fegetenv (MSVCR120.@)
1228 int CDECL MSVCRT_fegetenv(MSVCRT_fenv_t *env)
1230 env->control = _controlfp(0, 0) & (MSVCRT__EM_INEXACT | MSVCRT__EM_UNDERFLOW |
1231 MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID);
1232 env->status = _statusfp();
1233 return 0;
1235 #endif
1237 #if _MSVCR_VER>=140
1238 /*********************************************************************
1239 * __fpe_flt_rounds (UCRTBASE.@)
1241 int CDECL __fpe_flt_rounds(void)
1243 unsigned int fpc = _controlfp(0, 0) & MSVCRT__RC_CHOP;
1245 TRACE("()\n");
1247 switch(fpc) {
1248 case MSVCRT__RC_CHOP: return 0;
1249 case MSVCRT__RC_NEAR: return 1;
1250 #ifdef _WIN64
1251 case MSVCRT__RC_UP: return 3;
1252 default: return 2;
1253 #else
1254 case MSVCRT__RC_UP: return 2;
1255 default: return 3;
1256 #endif
1259 #endif
1261 #if _MSVCR_VER>=120
1263 /*********************************************************************
1264 * fegetround (MSVCR120.@)
1266 int CDECL MSVCRT_fegetround(void)
1268 return _controlfp(0, 0) & MSVCRT__RC_CHOP;
1271 /*********************************************************************
1272 * fesetround (MSVCR120.@)
1274 int CDECL MSVCRT_fesetround(int round_mode)
1276 if (round_mode & (~MSVCRT__RC_CHOP))
1277 return 1;
1278 _controlfp(round_mode, MSVCRT__RC_CHOP);
1279 return 0;
1282 #endif /* _MSVCR_VER>=120 */
1284 /*********************************************************************
1285 * _copysign (MSVCRT.@)
1287 double CDECL MSVCRT__copysign(double num, double sign)
1289 if (signbit(sign))
1290 return signbit(num) ? num : -num;
1291 return signbit(num) ? -num : num;
1294 /*********************************************************************
1295 * _finite (MSVCRT.@)
1297 int CDECL MSVCRT__finite(double num)
1299 return isfinite(num) != 0; /* See comment for _isnan() */
1302 /*********************************************************************
1303 * _fpreset (MSVCRT.@)
1305 void CDECL _fpreset(void)
1307 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1308 const unsigned int x86_cw = 0x27f;
1309 __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
1310 if (sse2_supported)
1312 const unsigned long sse2_cw = 0x1f80;
1313 __asm__ __volatile__( "ldmxcsr %0" : : "m" (sse2_cw) );
1315 #else
1316 FIXME( "not implemented\n" );
1317 #endif
1320 #if _MSVCR_VER>=120
1321 /*********************************************************************
1322 * fesetenv (MSVCR120.@)
1324 int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
1326 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1327 struct {
1328 WORD control_word;
1329 WORD unused1;
1330 WORD status_word;
1331 WORD unused2;
1332 WORD tag_word;
1333 WORD unused3;
1334 DWORD instruction_pointer;
1335 WORD code_segment;
1336 WORD unused4;
1337 DWORD operand_addr;
1338 WORD data_segment;
1339 WORD unused5;
1340 } fenv;
1342 TRACE( "(%p)\n", env );
1344 if (!env->control && !env->status) {
1345 _fpreset();
1346 return 0;
1349 __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
1351 fenv.control_word &= ~0x3d;
1352 if (env->control & MSVCRT__EM_INVALID) fenv.control_word |= 0x1;
1353 if (env->control & MSVCRT__EM_ZERODIVIDE) fenv.control_word |= 0x4;
1354 if (env->control & MSVCRT__EM_OVERFLOW) fenv.control_word |= 0x8;
1355 if (env->control & MSVCRT__EM_UNDERFLOW) fenv.control_word |= 0x10;
1356 if (env->control & MSVCRT__EM_INEXACT) fenv.control_word |= 0x20;
1358 fenv.status_word &= ~0x3d;
1359 if (env->status & MSVCRT__SW_INVALID) fenv.status_word |= 0x1;
1360 if (env->status & MSVCRT__SW_ZERODIVIDE) fenv.status_word |= 0x4;
1361 if (env->status & MSVCRT__SW_OVERFLOW) fenv.status_word |= 0x8;
1362 if (env->status & MSVCRT__SW_UNDERFLOW) fenv.status_word |= 0x10;
1363 if (env->status & MSVCRT__SW_INEXACT) fenv.status_word |= 0x20;
1365 __asm__ __volatile__( "fldenv %0" : : "m" (fenv) : "st", "st(1)",
1366 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
1368 if (sse2_supported)
1370 DWORD fpword;
1372 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1373 fpword &= ~0x1e80;
1374 if (env->control & MSVCRT__EM_INVALID) fpword |= 0x80;
1375 if (env->control & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
1376 if (env->control & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
1377 if (env->control & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
1378 if (env->control & MSVCRT__EM_INEXACT) fpword |= 0x1000;
1379 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1382 return 0;
1383 #else
1384 FIXME( "not implemented\n" );
1385 #endif
1386 return 1;
1388 #endif
1390 /*********************************************************************
1391 * _isnan (MSVCRT.@)
1393 INT CDECL MSVCRT__isnan(double num)
1395 /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
1396 * Do the same, as the result may be used in calculations
1398 return isnan(num) != 0;
1401 /*********************************************************************
1402 * _j0 (MSVCRT.@)
1404 double CDECL MSVCRT__j0(double num)
1406 /* FIXME: errno handling */
1407 #ifdef HAVE_J0
1408 return j0(num);
1409 #else
1410 FIXME("not implemented\n");
1411 return 0;
1412 #endif
1415 /*********************************************************************
1416 * _j1 (MSVCRT.@)
1418 double CDECL MSVCRT__j1(double num)
1420 /* FIXME: errno handling */
1421 #ifdef HAVE_J1
1422 return j1(num);
1423 #else
1424 FIXME("not implemented\n");
1425 return 0;
1426 #endif
1429 /*********************************************************************
1430 * _jn (MSVCRT.@)
1432 double CDECL MSVCRT__jn(int n, double num)
1434 /* FIXME: errno handling */
1435 #ifdef HAVE_JN
1436 return jn(n, num);
1437 #else
1438 FIXME("not implemented\n");
1439 return 0;
1440 #endif
1443 /*********************************************************************
1444 * _y0 (MSVCRT.@)
1446 double CDECL MSVCRT__y0(double num)
1448 double retval;
1449 if (!isfinite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1450 #ifdef HAVE_Y0
1451 retval = y0(num);
1452 if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1454 *MSVCRT__errno() = MSVCRT_EDOM;
1455 retval = NAN;
1457 #else
1458 FIXME("not implemented\n");
1459 retval = 0;
1460 #endif
1461 return retval;
1464 /*********************************************************************
1465 * _y1 (MSVCRT.@)
1467 double CDECL MSVCRT__y1(double num)
1469 double retval;
1470 if (!isfinite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1471 #ifdef HAVE_Y1
1472 retval = y1(num);
1473 if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1475 *MSVCRT__errno() = MSVCRT_EDOM;
1476 retval = NAN;
1478 #else
1479 FIXME("not implemented\n");
1480 retval = 0;
1481 #endif
1482 return retval;
1485 /*********************************************************************
1486 * _yn (MSVCRT.@)
1488 double CDECL MSVCRT__yn(int order, double num)
1490 double retval;
1491 if (!isfinite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1492 #ifdef HAVE_YN
1493 retval = yn(order,num);
1494 if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1496 *MSVCRT__errno() = MSVCRT_EDOM;
1497 retval = NAN;
1499 #else
1500 FIXME("not implemented\n");
1501 retval = 0;
1502 #endif
1503 return retval;
1506 #if _MSVCR_VER>=120
1508 /*********************************************************************
1509 * _nearbyint (MSVCR120.@)
1511 double CDECL MSVCRT_nearbyint(double num)
1513 #ifdef HAVE_NEARBYINT
1514 return nearbyint(num);
1515 #else
1516 return num >= 0 ? floor(num + 0.5) : ceil(num - 0.5);
1517 #endif
1520 /*********************************************************************
1521 * _nearbyintf (MSVCR120.@)
1523 float CDECL MSVCRT_nearbyintf(float num)
1525 #ifdef HAVE_NEARBYINTF
1526 return nearbyintf(num);
1527 #else
1528 return MSVCRT_nearbyint(num);
1529 #endif
1532 #endif /* _MSVCR_VER>=120 */
1534 /*********************************************************************
1535 * _nextafter (MSVCRT.@)
1537 double CDECL MSVCRT__nextafter(double num, double next)
1539 double retval;
1540 if (!isfinite(num) || !isfinite(next)) *MSVCRT__errno() = MSVCRT_EDOM;
1541 retval = nextafter(num,next);
1542 return retval;
1545 /*********************************************************************
1546 * _ecvt (MSVCRT.@)
1548 char * CDECL MSVCRT__ecvt( double number, int ndigits, int *decpt, int *sign )
1550 int prec, len;
1551 thread_data_t *data = msvcrt_get_thread_data();
1552 /* FIXME: check better for overflow (native supports over 300 chars) */
1553 ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
1554 * 4 for exponent and one for
1555 * terminating '\0' */
1556 if (!data->efcvt_buffer)
1557 data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
1559 if( number < 0) {
1560 *sign = TRUE;
1561 number = -number;
1562 } else
1563 *sign = FALSE;
1564 /* handle cases with zero ndigits or less */
1565 prec = ndigits;
1566 if( prec < 1) prec = 2;
1567 len = snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
1568 /* take the decimal "point away */
1569 if( prec != 1)
1570 memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
1571 /* take the exponential "e" out */
1572 data->efcvt_buffer[ prec] = '\0';
1573 /* read the exponent */
1574 sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
1575 (*decpt)++;
1576 /* adjust for some border cases */
1577 if( data->efcvt_buffer[0] == '0')/* value is zero */
1578 *decpt = 0;
1579 /* handle cases with zero ndigits or less */
1580 if( ndigits < 1){
1581 if( data->efcvt_buffer[ 0] >= '5')
1582 (*decpt)++;
1583 data->efcvt_buffer[ 0] = '\0';
1585 TRACE("out=\"%s\"\n",data->efcvt_buffer);
1586 return data->efcvt_buffer;
1589 /*********************************************************************
1590 * _ecvt_s (MSVCRT.@)
1592 int CDECL MSVCRT__ecvt_s( char *buffer, MSVCRT_size_t length, double number, int ndigits, int *decpt, int *sign )
1594 int prec, len;
1595 char *result;
1596 const char infret[] = "1#INF";
1598 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return MSVCRT_EINVAL;
1599 if (!MSVCRT_CHECK_PMT(decpt != NULL)) return MSVCRT_EINVAL;
1600 if (!MSVCRT_CHECK_PMT(sign != NULL)) return MSVCRT_EINVAL;
1601 if (!MSVCRT_CHECK_PMT_ERR( length > 2, MSVCRT_ERANGE )) return MSVCRT_ERANGE;
1602 if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, MSVCRT_ERANGE )) return MSVCRT_ERANGE;
1604 /* special case - inf */
1605 if(number == HUGE_VAL || number == -HUGE_VAL)
1607 memset(buffer, '0', ndigits);
1608 memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
1609 buffer[ndigits] = '\0';
1610 (*decpt) = 1;
1611 if(number == -HUGE_VAL)
1612 (*sign) = 1;
1613 else
1614 (*sign) = 0;
1615 return 0;
1617 /* handle cases with zero ndigits or less */
1618 prec = ndigits;
1619 if( prec < 1) prec = 2;
1620 result = MSVCRT_malloc(prec + 7);
1622 if( number < 0) {
1623 *sign = TRUE;
1624 number = -number;
1625 } else
1626 *sign = FALSE;
1627 len = snprintf(result, prec + 7, "%.*le", prec - 1, number);
1628 /* take the decimal "point away */
1629 if( prec != 1)
1630 memmove( result + 1, result + 2, len - 1 );
1631 /* take the exponential "e" out */
1632 result[ prec] = '\0';
1633 /* read the exponent */
1634 sscanf( result + prec + 1, "%d", decpt);
1635 (*decpt)++;
1636 /* adjust for some border cases */
1637 if( result[0] == '0')/* value is zero */
1638 *decpt = 0;
1639 /* handle cases with zero ndigits or less */
1640 if( ndigits < 1){
1641 if( result[ 0] >= '5')
1642 (*decpt)++;
1643 result[ 0] = '\0';
1645 memcpy( buffer, result, max(ndigits + 1, 1) );
1646 MSVCRT_free( result );
1647 return 0;
1650 /***********************************************************************
1651 * _fcvt (MSVCRT.@)
1653 char * CDECL MSVCRT__fcvt( double number, int ndigits, int *decpt, int *sign )
1655 thread_data_t *data = msvcrt_get_thread_data();
1656 int stop, dec1, dec2;
1657 char *ptr1, *ptr2, *first;
1658 char buf[80]; /* ought to be enough */
1660 if (!data->efcvt_buffer)
1661 data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
1663 if (number < 0)
1665 *sign = 1;
1666 number = -number;
1667 } else *sign = 0;
1669 stop = snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1670 ptr1 = buf;
1671 ptr2 = data->efcvt_buffer;
1672 first = NULL;
1673 dec1 = 0;
1674 dec2 = 0;
1676 /* For numbers below the requested resolution, work out where
1677 the decimal point will be rather than finding it in the string */
1678 if (number < 1.0 && number > 0.0) {
1679 dec2 = log10(number + 1e-10);
1680 if (-dec2 <= ndigits) dec2 = 0;
1683 /* If requested digits is zero or less, we will need to truncate
1684 * the returned string */
1685 if (ndigits < 1) {
1686 stop += ndigits;
1689 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1690 while (*ptr1 != '\0' && *ptr1 != '.') {
1691 if (!first) first = ptr2;
1692 if ((ptr1 - buf) < stop) {
1693 *ptr2++ = *ptr1++;
1694 } else {
1695 ptr1++;
1697 dec1++;
1700 if (ndigits > 0) {
1701 ptr1++;
1702 if (!first) {
1703 while (*ptr1 == '0') { /* Process leading zeroes */
1704 *ptr2++ = *ptr1++;
1705 dec1--;
1708 while (*ptr1 != '\0') {
1709 if (!first) first = ptr2;
1710 *ptr2++ = *ptr1++;
1714 *ptr2 = '\0';
1716 /* We never found a non-zero digit, then our number is either
1717 * smaller than the requested precision, or 0.0 */
1718 if (!first) {
1719 if (number > 0.0) {
1720 first = ptr2;
1721 } else {
1722 first = data->efcvt_buffer;
1723 dec1 = 0;
1727 *decpt = dec2 ? dec2 : dec1;
1728 return first;
1731 /***********************************************************************
1732 * _fcvt_s (MSVCRT.@)
1734 int CDECL MSVCRT__fcvt_s(char* outbuffer, MSVCRT_size_t size, double number, int ndigits, int *decpt, int *sign)
1736 int stop, dec1, dec2;
1737 char *ptr1, *ptr2, *first;
1738 char buf[80]; /* ought to be enough */
1740 if (!outbuffer || !decpt || !sign || size == 0)
1742 *MSVCRT__errno() = MSVCRT_EINVAL;
1743 return MSVCRT_EINVAL;
1746 if (number < 0)
1748 *sign = 1;
1749 number = -number;
1750 } else *sign = 0;
1752 stop = snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1753 ptr1 = buf;
1754 ptr2 = outbuffer;
1755 first = NULL;
1756 dec1 = 0;
1757 dec2 = 0;
1759 /* For numbers below the requested resolution, work out where
1760 the decimal point will be rather than finding it in the string */
1761 if (number < 1.0 && number > 0.0) {
1762 dec2 = log10(number + 1e-10);
1763 if (-dec2 <= ndigits) dec2 = 0;
1766 /* If requested digits is zero or less, we will need to truncate
1767 * the returned string */
1768 if (ndigits < 1) {
1769 stop += ndigits;
1772 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1773 while (*ptr1 != '\0' && *ptr1 != '.') {
1774 if (!first) first = ptr2;
1775 if ((ptr1 - buf) < stop) {
1776 if (size > 1) {
1777 *ptr2++ = *ptr1++;
1778 size--;
1780 } else {
1781 ptr1++;
1783 dec1++;
1786 if (ndigits > 0) {
1787 ptr1++;
1788 if (!first) {
1789 while (*ptr1 == '0') { /* Process leading zeroes */
1790 if (number == 0.0 && size > 1) {
1791 *ptr2++ = '0';
1792 size--;
1794 ptr1++;
1795 dec1--;
1798 while (*ptr1 != '\0') {
1799 if (!first) first = ptr2;
1800 if (size > 1) {
1801 *ptr2++ = *ptr1++;
1802 size--;
1807 *ptr2 = '\0';
1809 /* We never found a non-zero digit, then our number is either
1810 * smaller than the requested precision, or 0.0 */
1811 if (!first && (number <= 0.0))
1812 dec1 = 0;
1814 *decpt = dec2 ? dec2 : dec1;
1815 return 0;
1818 /***********************************************************************
1819 * _gcvt (MSVCRT.@)
1821 char * CDECL MSVCRT__gcvt( double number, int ndigit, char *buff )
1823 if(!buff) {
1824 *MSVCRT__errno() = MSVCRT_EINVAL;
1825 return NULL;
1828 if(ndigit < 0) {
1829 *MSVCRT__errno() = MSVCRT_ERANGE;
1830 return NULL;
1833 MSVCRT_sprintf(buff, "%.*g", ndigit, number);
1834 return buff;
1837 /***********************************************************************
1838 * _gcvt_s (MSVCRT.@)
1840 int CDECL MSVCRT__gcvt_s(char *buff, MSVCRT_size_t size, double number, int digits)
1842 int len;
1844 if(!buff) {
1845 *MSVCRT__errno() = MSVCRT_EINVAL;
1846 return MSVCRT_EINVAL;
1849 if( digits<0 || digits>=size) {
1850 if(size)
1851 buff[0] = '\0';
1853 *MSVCRT__errno() = MSVCRT_ERANGE;
1854 return MSVCRT_ERANGE;
1857 len = MSVCRT__scprintf("%.*g", digits, number);
1858 if(len > size) {
1859 buff[0] = '\0';
1860 *MSVCRT__errno() = MSVCRT_ERANGE;
1861 return MSVCRT_ERANGE;
1864 MSVCRT_sprintf(buff, "%.*g", digits, number);
1865 return 0;
1868 #include <stdlib.h> /* div_t, ldiv_t */
1870 /*********************************************************************
1871 * div (MSVCRT.@)
1872 * VERSION
1873 * [i386] Windows binary compatible - returns the struct in eax/edx.
1875 #ifdef __i386__
1876 unsigned __int64 CDECL MSVCRT_div(int num, int denom)
1878 div_t dt = div(num,denom);
1879 return ((unsigned __int64)dt.rem << 32) | (unsigned int)dt.quot;
1881 #else
1882 /*********************************************************************
1883 * div (MSVCRT.@)
1884 * VERSION
1885 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1887 MSVCRT_div_t CDECL MSVCRT_div(int num, int denom)
1889 div_t dt = div(num,denom);
1890 MSVCRT_div_t ret;
1891 ret.quot = dt.quot;
1892 ret.rem = dt.rem;
1894 return ret;
1897 #endif /* ifdef __i386__ */
1900 /*********************************************************************
1901 * ldiv (MSVCRT.@)
1902 * VERSION
1903 * [i386] Windows binary compatible - returns the struct in eax/edx.
1905 #ifdef __i386__
1906 unsigned __int64 CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1908 ldiv_t ldt = ldiv(num,denom);
1909 return ((unsigned __int64)ldt.rem << 32) | (MSVCRT_ulong)ldt.quot;
1911 #else
1912 /*********************************************************************
1913 * ldiv (MSVCRT.@)
1914 * VERSION
1915 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1917 MSVCRT_ldiv_t CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1919 ldiv_t result = ldiv(num,denom);
1921 MSVCRT_ldiv_t ret;
1922 ret.quot = result.quot;
1923 ret.rem = result.rem;
1925 return ret;
1927 #endif /* ifdef __i386__ */
1929 #if _MSVCR_VER>=100
1930 /*********************************************************************
1931 * lldiv (MSVCR100.@)
1933 MSVCRT_lldiv_t* CDECL MSVCRT_lldiv(MSVCRT_lldiv_t *ret,
1934 MSVCRT_longlong num, MSVCRT_longlong denom)
1936 ret->quot = num / denom;
1937 ret->rem = num % denom;
1939 return ret;
1941 #endif
1943 #ifdef __i386__
1945 /*********************************************************************
1946 * _adjust_fdiv (MSVCRT.@)
1947 * Used by the MSVC compiler to work around the Pentium FDIV bug.
1949 int MSVCRT__adjust_fdiv = 0;
1951 /***********************************************************************
1952 * _adj_fdiv_m16i (MSVCRT.@)
1954 * NOTE
1955 * I _think_ this function is intended to work around the Pentium
1956 * fdiv bug.
1958 void __stdcall _adj_fdiv_m16i( short arg )
1960 TRACE("(): stub\n");
1963 /***********************************************************************
1964 * _adj_fdiv_m32 (MSVCRT.@)
1966 * NOTE
1967 * I _think_ this function is intended to work around the Pentium
1968 * fdiv bug.
1970 void __stdcall _adj_fdiv_m32( unsigned int arg )
1972 TRACE("(): stub\n");
1975 /***********************************************************************
1976 * _adj_fdiv_m32i (MSVCRT.@)
1978 * NOTE
1979 * I _think_ this function is intended to work around the Pentium
1980 * fdiv bug.
1982 void __stdcall _adj_fdiv_m32i( int arg )
1984 TRACE("(): stub\n");
1987 /***********************************************************************
1988 * _adj_fdiv_m64 (MSVCRT.@)
1990 * NOTE
1991 * I _think_ this function is intended to work around the Pentium
1992 * fdiv bug.
1994 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
1996 TRACE("(): stub\n");
1999 /***********************************************************************
2000 * _adj_fdiv_r (MSVCRT.@)
2001 * FIXME
2002 * This function is likely to have the wrong number of arguments.
2004 * NOTE
2005 * I _think_ this function is intended to work around the Pentium
2006 * fdiv bug.
2008 void _adj_fdiv_r(void)
2010 TRACE("(): stub\n");
2013 /***********************************************************************
2014 * _adj_fdivr_m16i (MSVCRT.@)
2016 * NOTE
2017 * I _think_ this function is intended to work around the Pentium
2018 * fdiv bug.
2020 void __stdcall _adj_fdivr_m16i( short arg )
2022 TRACE("(): stub\n");
2025 /***********************************************************************
2026 * _adj_fdivr_m32 (MSVCRT.@)
2028 * NOTE
2029 * I _think_ this function is intended to work around the Pentium
2030 * fdiv bug.
2032 void __stdcall _adj_fdivr_m32( unsigned int arg )
2034 TRACE("(): stub\n");
2037 /***********************************************************************
2038 * _adj_fdivr_m32i (MSVCRT.@)
2040 * NOTE
2041 * I _think_ this function is intended to work around the Pentium
2042 * fdiv bug.
2044 void __stdcall _adj_fdivr_m32i( int arg )
2046 TRACE("(): stub\n");
2049 /***********************************************************************
2050 * _adj_fdivr_m64 (MSVCRT.@)
2052 * NOTE
2053 * I _think_ this function is intended to work around the Pentium
2054 * fdiv bug.
2056 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
2058 TRACE("(): stub\n");
2061 /***********************************************************************
2062 * _adj_fpatan (MSVCRT.@)
2063 * FIXME
2064 * This function is likely to have the wrong number of arguments.
2066 * NOTE
2067 * I _think_ this function is intended to work around the Pentium
2068 * fdiv bug.
2070 void _adj_fpatan(void)
2072 TRACE("(): stub\n");
2075 /***********************************************************************
2076 * _adj_fprem (MSVCRT.@)
2077 * FIXME
2078 * This function is likely to have the wrong number of arguments.
2080 * NOTE
2081 * I _think_ this function is intended to work around the Pentium
2082 * fdiv bug.
2084 void _adj_fprem(void)
2086 TRACE("(): stub\n");
2089 /***********************************************************************
2090 * _adj_fprem1 (MSVCRT.@)
2091 * FIXME
2092 * This function is likely to have the wrong number of arguments.
2094 * NOTE
2095 * I _think_ this function is intended to work around the Pentium
2096 * fdiv bug.
2098 void _adj_fprem1(void)
2100 TRACE("(): stub\n");
2103 /***********************************************************************
2104 * _adj_fptan (MSVCRT.@)
2105 * FIXME
2106 * This function is likely to have the wrong number of arguments.
2108 * NOTE
2109 * I _think_ this function is intended to work around the Pentium
2110 * fdiv bug.
2112 void _adj_fptan(void)
2114 TRACE("(): stub\n");
2117 /***********************************************************************
2118 * _safe_fdiv (MSVCRT.@)
2119 * FIXME
2120 * This function is likely to have the wrong number of arguments.
2122 * NOTE
2123 * I _think_ this function is intended to work around the Pentium
2124 * fdiv bug.
2126 void _safe_fdiv(void)
2128 TRACE("(): stub\n");
2131 /***********************************************************************
2132 * _safe_fdivr (MSVCRT.@)
2133 * FIXME
2134 * This function is likely to have the wrong number of arguments.
2136 * NOTE
2137 * I _think_ this function is intended to work around the Pentium
2138 * fdiv bug.
2140 void _safe_fdivr(void)
2142 TRACE("(): stub\n");
2145 /***********************************************************************
2146 * _safe_fprem (MSVCRT.@)
2147 * FIXME
2148 * This function is likely to have the wrong number of arguments.
2150 * NOTE
2151 * I _think_ this function is intended to work around the Pentium
2152 * fdiv bug.
2154 void _safe_fprem(void)
2156 TRACE("(): stub\n");
2159 /***********************************************************************
2160 * _safe_fprem1 (MSVCRT.@)
2162 * FIXME
2163 * This function is likely to have the wrong number of arguments.
2165 * NOTE
2166 * I _think_ this function is intended to work around the Pentium
2167 * fdiv bug.
2169 void _safe_fprem1(void)
2171 TRACE("(): stub\n");
2174 /***********************************************************************
2175 * __libm_sse2_acos (MSVCRT.@)
2177 void __cdecl MSVCRT___libm_sse2_acos(void)
2179 double d;
2180 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2181 d = acos( d );
2182 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2185 /***********************************************************************
2186 * __libm_sse2_acosf (MSVCRT.@)
2188 void __cdecl MSVCRT___libm_sse2_acosf(void)
2190 float f;
2191 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2192 f = acosf( f );
2193 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2196 /***********************************************************************
2197 * __libm_sse2_asin (MSVCRT.@)
2199 void __cdecl MSVCRT___libm_sse2_asin(void)
2201 double d;
2202 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2203 d = asin( d );
2204 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2207 /***********************************************************************
2208 * __libm_sse2_asinf (MSVCRT.@)
2210 void __cdecl MSVCRT___libm_sse2_asinf(void)
2212 float f;
2213 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2214 f = asinf( f );
2215 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2218 /***********************************************************************
2219 * __libm_sse2_atan (MSVCRT.@)
2221 void __cdecl MSVCRT___libm_sse2_atan(void)
2223 double d;
2224 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2225 d = atan( d );
2226 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2229 /***********************************************************************
2230 * __libm_sse2_atan2 (MSVCRT.@)
2232 void __cdecl MSVCRT___libm_sse2_atan2(void)
2234 double d1, d2;
2235 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2236 d1 = atan2( d1, d2 );
2237 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2240 /***********************************************************************
2241 * __libm_sse2_atanf (MSVCRT.@)
2243 void __cdecl MSVCRT___libm_sse2_atanf(void)
2245 float f;
2246 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2247 f = atanf( f );
2248 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2251 /***********************************************************************
2252 * __libm_sse2_cos (MSVCRT.@)
2254 void __cdecl MSVCRT___libm_sse2_cos(void)
2256 double d;
2257 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2258 d = cos( d );
2259 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2262 /***********************************************************************
2263 * __libm_sse2_cosf (MSVCRT.@)
2265 void __cdecl MSVCRT___libm_sse2_cosf(void)
2267 float f;
2268 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2269 f = cosf( f );
2270 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2273 /***********************************************************************
2274 * __libm_sse2_exp (MSVCRT.@)
2276 void __cdecl MSVCRT___libm_sse2_exp(void)
2278 double d;
2279 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2280 d = exp( d );
2281 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2284 /***********************************************************************
2285 * __libm_sse2_expf (MSVCRT.@)
2287 void __cdecl MSVCRT___libm_sse2_expf(void)
2289 float f;
2290 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2291 f = expf( f );
2292 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2295 /***********************************************************************
2296 * __libm_sse2_log (MSVCRT.@)
2298 void __cdecl MSVCRT___libm_sse2_log(void)
2300 double d;
2301 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2302 d = log( d );
2303 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2306 /***********************************************************************
2307 * __libm_sse2_log10 (MSVCRT.@)
2309 void __cdecl MSVCRT___libm_sse2_log10(void)
2311 double d;
2312 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2313 d = log10( d );
2314 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2317 /***********************************************************************
2318 * __libm_sse2_log10f (MSVCRT.@)
2320 void __cdecl MSVCRT___libm_sse2_log10f(void)
2322 float f;
2323 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2324 f = log10f( f );
2325 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2328 /***********************************************************************
2329 * __libm_sse2_logf (MSVCRT.@)
2331 void __cdecl MSVCRT___libm_sse2_logf(void)
2333 float f;
2334 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2335 f = logf( f );
2336 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2339 /***********************************************************************
2340 * __libm_sse2_pow (MSVCRT.@)
2342 void __cdecl MSVCRT___libm_sse2_pow(void)
2344 double d1, d2;
2345 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2346 d1 = pow( d1, d2 );
2347 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2350 /***********************************************************************
2351 * __libm_sse2_powf (MSVCRT.@)
2353 void __cdecl MSVCRT___libm_sse2_powf(void)
2355 float f1, f2;
2356 __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
2357 f1 = powf( f1, f2 );
2358 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
2361 /***********************************************************************
2362 * __libm_sse2_sin (MSVCRT.@)
2364 void __cdecl MSVCRT___libm_sse2_sin(void)
2366 double d;
2367 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2368 d = sin( d );
2369 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2372 /***********************************************************************
2373 * __libm_sse2_sinf (MSVCRT.@)
2375 void __cdecl MSVCRT___libm_sse2_sinf(void)
2377 float f;
2378 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2379 f = sinf( f );
2380 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2383 /***********************************************************************
2384 * __libm_sse2_tan (MSVCRT.@)
2386 void __cdecl MSVCRT___libm_sse2_tan(void)
2388 double d;
2389 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2390 d = tan( d );
2391 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2394 /***********************************************************************
2395 * __libm_sse2_tanf (MSVCRT.@)
2397 void __cdecl MSVCRT___libm_sse2_tanf(void)
2399 float f;
2400 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2401 f = tanf( f );
2402 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2405 /***********************************************************************
2406 * __libm_sse2_sqrt_precise (MSVCR110.@)
2408 void __cdecl MSVCRT___libm_sse2_sqrt_precise(void)
2410 double d;
2411 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2412 d = sqrt( d );
2413 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2416 #endif /* __i386__ */
2418 /*********************************************************************
2419 * cbrt (MSVCR120.@)
2421 double CDECL MSVCR120_cbrt(double x)
2423 #ifdef HAVE_CBRT
2424 return cbrt(x);
2425 #else
2426 return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0);
2427 #endif
2430 /*********************************************************************
2431 * cbrtf (MSVCR120.@)
2433 float CDECL MSVCR120_cbrtf(float x)
2435 #ifdef HAVE_CBRTF
2436 return cbrtf(x);
2437 #else
2438 return MSVCR120_cbrt(x);
2439 #endif
2442 /*********************************************************************
2443 * cbrtl (MSVCR120.@)
2445 LDOUBLE CDECL MSVCR120_cbrtl(LDOUBLE x)
2447 return MSVCR120_cbrt(x);
2450 /*********************************************************************
2451 * exp2 (MSVCR120.@)
2453 double CDECL MSVCR120_exp2(double x)
2455 #ifdef HAVE_EXP2
2456 double ret = exp2(x);
2457 #else
2458 double ret = pow(2, x);
2459 #endif
2460 if (isfinite(x) && !isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2461 return ret;
2464 /*********************************************************************
2465 * exp2f (MSVCR120.@)
2467 float CDECL MSVCR120_exp2f(float x)
2469 #ifdef HAVE_EXP2F
2470 float ret = exp2f(x);
2471 if (finitef(x) && !finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2472 return ret;
2473 #else
2474 return MSVCR120_exp2(x);
2475 #endif
2478 /*********************************************************************
2479 * exp2l (MSVCR120.@)
2481 LDOUBLE CDECL MSVCR120_exp2l(LDOUBLE x)
2483 return MSVCR120_exp2(x);
2486 /*********************************************************************
2487 * expm1 (MSVCR120.@)
2489 double CDECL MSVCR120_expm1(double x)
2491 #ifdef HAVE_EXPM1
2492 double ret = expm1(x);
2493 #else
2494 double ret = exp(x) - 1;
2495 #endif
2496 if (isfinite(x) && !isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2497 return ret;
2500 /*********************************************************************
2501 * expm1f (MSVCR120.@)
2503 float CDECL MSVCR120_expm1f(float x)
2505 #ifdef HAVE_EXPM1F
2506 float ret = expm1f(x);
2507 #else
2508 float ret = exp(x) - 1;
2509 #endif
2510 if (finitef(x) && !finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
2511 return ret;
2514 /*********************************************************************
2515 * expm1l (MSVCR120.@)
2517 LDOUBLE CDECL MSVCR120_expm1l(LDOUBLE x)
2519 return MSVCR120_expm1(x);
2522 /*********************************************************************
2523 * log1p (MSVCR120.@)
2525 double CDECL MSVCR120_log1p(double x)
2527 if (x < -1) *MSVCRT__errno() = MSVCRT_EDOM;
2528 else if (x == -1) *MSVCRT__errno() = MSVCRT_ERANGE;
2529 #ifdef HAVE_LOG1P
2530 return log1p(x);
2531 #else
2532 return log(1 + x);
2533 #endif
2536 /*********************************************************************
2537 * log1pf (MSVCR120.@)
2539 float CDECL MSVCR120_log1pf(float x)
2541 if (x < -1) *MSVCRT__errno() = MSVCRT_EDOM;
2542 else if (x == -1) *MSVCRT__errno() = MSVCRT_ERANGE;
2543 #ifdef HAVE_LOG1PF
2544 return log1pf(x);
2545 #else
2546 return log(1 + x);
2547 #endif
2550 /*********************************************************************
2551 * log1pl (MSVCR120.@)
2553 LDOUBLE CDECL MSVCR120_log1pl(LDOUBLE x)
2555 return MSVCR120_log1p(x);
2558 /*********************************************************************
2559 * log2 (MSVCR120.@)
2561 double CDECL MSVCR120_log2(double x)
2563 if (x < 0) *MSVCRT__errno() = MSVCRT_EDOM;
2564 else if (x == 0) *MSVCRT__errno() = MSVCRT_ERANGE;
2565 #ifdef HAVE_LOG2
2566 return log2(x);
2567 #else
2568 return log(x) / log(2);
2569 #endif
2572 /*********************************************************************
2573 * log2f (MSVCR120.@)
2575 float CDECL MSVCR120_log2f(float x)
2577 #ifdef HAVE_LOG2F
2578 if (x < 0) *MSVCRT__errno() = MSVCRT_EDOM;
2579 else if (x == 0) *MSVCRT__errno() = MSVCRT_ERANGE;
2580 return log2f(x);
2581 #else
2582 return MSVCR120_log2(x);
2583 #endif
2586 /*********************************************************************
2587 * log2l (MSVCR120.@)
2589 LDOUBLE CDECL MSVCR120_log2l(LDOUBLE x)
2591 return MSVCR120_log2(x);
2594 /*********************************************************************
2595 * rint (MSVCR120.@)
2597 double CDECL MSVCR120_rint(double x)
2599 return rint(x);
2602 /*********************************************************************
2603 * rintf (MSVCR120.@)
2605 float CDECL MSVCR120_rintf(float x)
2607 return rintf(x);
2610 /*********************************************************************
2611 * rintl (MSVCR120.@)
2613 LDOUBLE CDECL MSVCR120_rintl(LDOUBLE x)
2615 return MSVCR120_rint(x);
2618 /*********************************************************************
2619 * lrint (MSVCR120.@)
2621 MSVCRT_long CDECL MSVCR120_lrint(double x)
2623 return lrint(x);
2626 /*********************************************************************
2627 * lrintf (MSVCR120.@)
2629 MSVCRT_long CDECL MSVCR120_lrintf(float x)
2631 return lrintf(x);
2634 /*********************************************************************
2635 * lrintl (MSVCR120.@)
2637 MSVCRT_long CDECL MSVCR120_lrintl(LDOUBLE x)
2639 return MSVCR120_lrint(x);
2642 /*********************************************************************
2643 * llrint (MSVCR120.@)
2645 MSVCRT_longlong CDECL MSVCR120_llrint(double x)
2647 return llrint(x);
2650 /*********************************************************************
2651 * llrintf (MSVCR120.@)
2653 MSVCRT_longlong CDECL MSVCR120_llrintf(float x)
2655 return llrintf(x);
2658 /*********************************************************************
2659 * rintl (MSVCR120.@)
2661 MSVCRT_longlong CDECL MSVCR120_llrintl(LDOUBLE x)
2663 return MSVCR120_llrint(x);
2666 #if _MSVCR_VER>=120
2668 /*********************************************************************
2669 * round (MSVCR120.@)
2671 double CDECL MSVCR120_round(double x)
2673 #ifdef HAVE_ROUND
2674 return round(x);
2675 #else
2676 return MSVCR120_rint(x);
2677 #endif
2680 /*********************************************************************
2681 * roundf (MSVCR120.@)
2683 float CDECL MSVCR120_roundf(float x)
2685 #ifdef HAVE_ROUNDF
2686 return roundf(x);
2687 #else
2688 return MSVCR120_round(x);
2689 #endif
2692 /*********************************************************************
2693 * roundl (MSVCR120.@)
2695 LDOUBLE CDECL MSVCR120_roundl(LDOUBLE x)
2697 return MSVCR120_round(x);
2700 /*********************************************************************
2701 * lround (MSVCR120.@)
2703 MSVCRT_long CDECL MSVCR120_lround(double x)
2705 #ifdef HAVE_LROUND
2706 return lround(x);
2707 #else
2708 return MSVCR120_round(x);
2709 #endif
2712 /*********************************************************************
2713 * lroundf (MSVCR120.@)
2715 MSVCRT_long CDECL MSVCR120_lroundf(float x)
2717 #ifdef HAVE_LROUNDF
2718 return lroundf(x);
2719 #else
2720 return MSVCR120_lround(x);
2721 #endif
2724 /*********************************************************************
2725 * lroundl (MSVCR120.@)
2727 MSVCRT_long CDECL MSVCR120_lroundl(LDOUBLE x)
2729 return MSVCR120_lround(x);
2732 /*********************************************************************
2733 * llround (MSVCR120.@)
2735 MSVCRT_longlong CDECL MSVCR120_llround(double x)
2737 #ifdef HAVE_LLROUND
2738 return llround(x);
2739 #else
2740 return MSVCR120_round(x);
2741 #endif
2744 /*********************************************************************
2745 * llroundf (MSVCR120.@)
2747 MSVCRT_longlong CDECL MSVCR120_llroundf(float x)
2749 #ifdef HAVE_LLROUNDF
2750 return llroundf(x);
2751 #else
2752 return MSVCR120_llround(x);
2753 #endif
2756 /*********************************************************************
2757 * roundl (MSVCR120.@)
2759 MSVCRT_longlong CDECL MSVCR120_llroundl(LDOUBLE x)
2761 return MSVCR120_llround(x);
2764 /*********************************************************************
2765 * trunc (MSVCR120.@)
2767 double CDECL MSVCR120_trunc(double x)
2769 #ifdef HAVE_TRUNC
2770 return trunc(x);
2771 #else
2772 return (x > 0) ? floor(x) : ceil(x);
2773 #endif
2776 /*********************************************************************
2777 * truncf (MSVCR120.@)
2779 float CDECL MSVCR120_truncf(float x)
2781 #ifdef HAVE_TRUNCF
2782 return truncf(x);
2783 #else
2784 return MSVCR120_trunc(x);
2785 #endif
2788 /*********************************************************************
2789 * truncl (MSVCR120.@)
2791 LDOUBLE CDECL MSVCR120_truncl(LDOUBLE x)
2793 return MSVCR120_trunc(x);
2796 /*********************************************************************
2797 * _dclass (MSVCR120.@)
2799 short CDECL MSVCR120__dclass(double x)
2801 switch (MSVCRT__fpclass(x)) {
2802 case MSVCRT__FPCLASS_QNAN:
2803 case MSVCRT__FPCLASS_SNAN:
2804 return MSVCRT_FP_NAN;
2805 case MSVCRT__FPCLASS_NINF:
2806 case MSVCRT__FPCLASS_PINF:
2807 return MSVCRT_FP_INFINITE;
2808 case MSVCRT__FPCLASS_ND:
2809 case MSVCRT__FPCLASS_PD:
2810 return MSVCRT_FP_SUBNORMAL;
2811 case MSVCRT__FPCLASS_NN:
2812 case MSVCRT__FPCLASS_PN:
2813 default:
2814 return MSVCRT_FP_NORMAL;
2815 case MSVCRT__FPCLASS_NZ:
2816 case MSVCRT__FPCLASS_PZ:
2817 return MSVCRT_FP_ZERO;
2821 /*********************************************************************
2822 * _fdclass (MSVCR120.@)
2824 short CDECL MSVCR120__fdclass(float x)
2826 return MSVCR120__dclass(x);
2829 /*********************************************************************
2830 * _ldclass (MSVCR120.@)
2832 short CDECL MSVCR120__ldclass(LDOUBLE x)
2834 return MSVCR120__dclass(x);
2837 /*********************************************************************
2838 * _dtest (MSVCR120.@)
2840 short CDECL MSVCR120__dtest(double *x)
2842 return MSVCR120__dclass(*x);
2845 /*********************************************************************
2846 * _fdtest (MSVCR120.@)
2848 short CDECL MSVCR120__fdtest(float *x)
2850 return MSVCR120__dclass(*x);
2853 /*********************************************************************
2854 * _ldtest (MSVCR120.@)
2856 short CDECL MSVCR120__ldtest(LDOUBLE *x)
2858 return MSVCR120__dclass(*x);
2861 /*********************************************************************
2862 * erf (MSVCR120.@)
2864 double CDECL MSVCR120_erf(double x)
2866 #ifdef HAVE_ERF
2867 return erf(x);
2868 #else
2869 /* Abramowitz and Stegun approximation, maximum error: 1.5*10^-7 */
2870 double t, y;
2871 int sign = signbit(x);
2873 if (sign) x = -x;
2874 t = 1 / (1 + 0.3275911 * x);
2875 y = ((((1.061405429*t - 1.453152027)*t + 1.421413741)*t - 0.284496736)*t + 0.254829592)*t;
2876 y = 1.0 - y*exp(-x*x);
2877 return sign ? -y : y;
2878 #endif
2881 /*********************************************************************
2882 * erff (MSVCR120.@)
2884 float CDECL MSVCR120_erff(float x)
2886 #ifdef HAVE_ERFF
2887 return erff(x);
2888 #else
2889 return MSVCR120_erf(x);
2890 #endif
2893 /*********************************************************************
2894 * erfl (MSVCR120.@)
2896 LDOUBLE CDECL MSVCR120_erfl(LDOUBLE x)
2898 return MSVCR120_erf(x);
2901 /*********************************************************************
2902 * erfc (MSVCR120.@)
2904 double CDECL MSVCR120_erfc(double x)
2906 #ifdef HAVE_ERFC
2907 return erfc(x);
2908 #else
2909 return 1 - MSVCR120_erf(x);
2910 #endif
2913 /*********************************************************************
2914 * erfcf (MSVCR120.@)
2916 float CDECL MSVCR120_erfcf(float x)
2918 #ifdef HAVE_ERFCF
2919 return erfcf(x);
2920 #else
2921 return MSVCR120_erfc(x);
2922 #endif
2925 /*********************************************************************
2926 * erfcl (MSVCR120.@)
2928 LDOUBLE CDECL MSVCR120_erfcl(LDOUBLE x)
2930 return MSVCR120_erfc(x);
2933 /*********************************************************************
2934 * fmaxf (MSVCR120.@)
2936 float CDECL MSVCR120_fmaxf(float x, float y)
2938 if(isnan(x))
2939 return y;
2940 if(isnan(y))
2941 return x;
2942 if(x==0 && y==0)
2943 return signbit(x) ? y : x;
2944 return x<y ? y : x;
2947 /*********************************************************************
2948 * fmax (MSVCR120.@)
2950 double CDECL MSVCR120_fmax(double x, double y)
2952 if(isnan(x))
2953 return y;
2954 if(isnan(y))
2955 return x;
2956 if(x==0 && y==0)
2957 return signbit(x) ? y : x;
2958 return x<y ? y : x;
2961 /*********************************************************************
2962 * _fdsign (MSVCR120.@)
2964 int CDECL MSVCR120__fdsign(float x)
2966 return signbit(x) ? 0x8000 : 0;
2969 /*********************************************************************
2970 * _dsign (MSVCR120.@)
2972 int CDECL MSVCR120__dsign(double x)
2974 return signbit(x) ? 0x8000 : 0;
2978 /*********************************************************************
2979 * _dpcomp (MSVCR120.@)
2981 int CDECL MSVCR120__dpcomp(double x, double y)
2983 if(isnan(x) || isnan(y))
2984 return 0;
2986 if(x == y) return 2;
2987 return x < y ? 1 : 4;
2990 /*********************************************************************
2991 * _fdpcomp (MSVCR120.@)
2993 int CDECL MSVCR120__fdpcomp(float x, float y)
2995 return MSVCR120__dpcomp(x, y);
2998 /*********************************************************************
2999 * fminf (MSVCR120.@)
3001 float CDECL MSVCR120_fminf(float x, float y)
3003 if(isnan(x))
3004 return y;
3005 if(isnan(y))
3006 return x;
3007 if(x==0 && y==0)
3008 return signbit(x) ? x : y;
3009 return x<y ? x : y;
3012 /*********************************************************************
3013 * fmin (MSVCR120.@)
3015 double CDECL MSVCR120_fmin(double x, double y)
3017 if(isnan(x))
3018 return y;
3019 if(isnan(y))
3020 return x;
3021 if(x==0 && y==0)
3022 return signbit(x) ? x : y;
3023 return x<y ? x : y;
3026 /*********************************************************************
3027 * asinh (MSVCR120.@)
3029 double CDECL MSVCR120_asinh(double x)
3031 #ifdef HAVE_ASINH
3032 return asinh(x);
3033 #else
3034 if (!isfinite(x*x+1)) return log(2) + log(x);
3035 return log(x + sqrt(x*x+1));
3036 #endif
3039 /*********************************************************************
3040 * asinhf (MSVCR120.@)
3042 float CDECL MSVCR120_asinhf(float x)
3044 #ifdef HAVE_ASINHF
3045 return asinhf(x);
3046 #else
3047 return MSVCR120_asinh(x);
3048 #endif
3051 /*********************************************************************
3052 * asinhl (MSVCR120.@)
3054 LDOUBLE CDECL MSVCR120_asinhl(LDOUBLE x)
3056 return MSVCR120_asinh(x);
3059 /*********************************************************************
3060 * acosh (MSVCR120.@)
3062 double CDECL MSVCR120_acosh(double x)
3064 if (x < 1) *MSVCRT__errno() = MSVCRT_EDOM;
3066 #ifdef HAVE_ACOSH
3067 return acosh(x);
3068 #else
3069 if (x < 1) {
3070 MSVCRT_fenv_t env;
3072 MSVCRT_fegetenv(&env);
3073 env.status |= MSVCRT__SW_INVALID;
3074 MSVCRT_fesetenv(&env);
3075 return NAN;
3077 if (!isfinite(x*x)) return log(2) + log(x);
3078 return log(x + sqrt(x*x-1));
3079 #endif
3082 /*********************************************************************
3083 * acoshf (MSVCR120.@)
3085 float CDECL MSVCR120_acoshf(float x)
3087 #ifdef HAVE_ACOSHF
3088 if (x < 1) *MSVCRT__errno() = MSVCRT_EDOM;
3090 return acoshf(x);
3091 #else
3092 return MSVCR120_acosh(x);
3093 #endif
3096 /*********************************************************************
3097 * acoshl (MSVCR120.@)
3099 LDOUBLE CDECL MSVCR120_acoshl(LDOUBLE x)
3101 return MSVCR120_acosh(x);
3104 /*********************************************************************
3105 * atanh (MSVCR120.@)
3107 double CDECL MSVCR120_atanh(double x)
3109 double ret;
3111 if (x > 1 || x < -1) {
3112 MSVCRT_fenv_t env;
3114 *MSVCRT__errno() = MSVCRT_EDOM;
3116 /* on Linux atanh returns -NAN in this case */
3117 MSVCRT_fegetenv(&env);
3118 env.status |= MSVCRT__SW_INVALID;
3119 MSVCRT_fesetenv(&env);
3120 return NAN;
3123 #ifdef HAVE_ATANH
3124 ret = atanh(x);
3125 #else
3126 if (-1e-6 < x && x < 1e-6) ret = x + x*x*x/3;
3127 else ret = (log(1+x) - log(1-x)) / 2;
3128 #endif
3130 if (!isfinite(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
3131 return ret;
3134 /*********************************************************************
3135 * atanhf (MSVCR120.@)
3137 float CDECL MSVCR120_atanhf(float x)
3139 #ifdef HAVE_ATANHF
3140 float ret;
3142 if (x > 1 || x < -1) {
3143 MSVCRT_fenv_t env;
3145 *MSVCRT__errno() = MSVCRT_EDOM;
3147 MSVCRT_fegetenv(&env);
3148 env.status |= MSVCRT__SW_INVALID;
3149 MSVCRT_fesetenv(&env);
3150 return NAN;
3153 ret = atanhf(x);
3155 if (!finitef(ret)) *MSVCRT__errno() = MSVCRT_ERANGE;
3156 return ret;
3157 #else
3158 return MSVCR120_atanh(x);
3159 #endif
3162 /*********************************************************************
3163 * atanhl (MSVCR120.@)
3165 LDOUBLE CDECL MSVCR120_atanhl(LDOUBLE x)
3167 return MSVCR120_atanh(x);
3170 #endif /* _MSVCR_VER>=120 */
3172 /*********************************************************************
3173 * _scalb (MSVCRT.@)
3174 * scalbn (MSVCR120.@)
3175 * scalbln (MSVCR120.@)
3177 double CDECL MSVCRT__scalb(double num, MSVCRT_long power)
3179 return MSVCRT_ldexp(num, power);
3182 /*********************************************************************
3183 * _scalbf (MSVCRT.@)
3184 * scalbnf (MSVCR120.@)
3185 * scalblnf (MSVCR120.@)
3187 float CDECL MSVCRT__scalbf(float num, MSVCRT_long power)
3189 return MSVCRT_ldexp(num, power);
3192 #if _MSVCR_VER>=120
3194 /*********************************************************************
3195 * scalbnl (MSVCR120.@)
3196 * scalblnl (MSVCR120.@)
3198 LDOUBLE CDECL MSVCR120_scalbnl(LDOUBLE num, MSVCRT_long power)
3200 return MSVCRT__scalb(num, power);
3203 /*********************************************************************
3204 * remainder (MSVCR120.@)
3206 double CDECL MSVCR120_remainder(double x, double y)
3208 #ifdef HAVE_REMAINDER
3209 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3210 if(!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
3211 if(isnan(y) || y==0.0) *MSVCRT__errno() = MSVCRT_EDOM;
3212 return remainder(x, y);
3213 #else
3214 FIXME( "not implemented\n" );
3215 return 0.0;
3216 #endif
3219 /*********************************************************************
3220 * remainderf (MSVCR120.@)
3222 float CDECL MSVCR120_remainderf(float x, float y)
3224 #ifdef HAVE_REMAINDERF
3225 /* this matches 64-bit Windows. 32-bit Windows is slightly different */
3226 if(!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
3227 if(isnan(y) || y==0.0f) *MSVCRT__errno() = MSVCRT_EDOM;
3228 return remainderf(x, y);
3229 #else
3230 FIXME( "not implemented\n" );
3231 return 0.0f;
3232 #endif
3235 /*********************************************************************
3236 * remainderl (MSVCR120.@)
3238 LDOUBLE CDECL MSVCR120_remainderl(LDOUBLE x, LDOUBLE y)
3240 return MSVCR120_remainder(x, y);
3243 /*********************************************************************
3244 * lgamma (MSVCR120.@)
3246 double CDECL MSVCR120_lgamma(double x)
3248 #ifdef HAVE_LGAMMA
3249 return lgamma(x);
3250 #else
3251 FIXME( "not implemented\n" );
3252 return 0.0;
3253 #endif
3256 /*********************************************************************
3257 * lgammaf (MSVCR120.@)
3259 float CDECL MSVCR120_lgammaf(float x)
3261 #ifdef HAVE_LGAMMAF
3262 return lgammaf(x);
3263 #else
3264 FIXME( "not implemented\n" );
3265 return 0.0f;
3266 #endif
3269 /*********************************************************************
3270 * lgammal (MSVCR120.@)
3272 LDOUBLE CDECL MSVCR120_lgammal(LDOUBLE x)
3274 return MSVCR120_lgamma(x);
3277 /*********************************************************************
3278 * nan (MSVCR120.@)
3280 double CDECL MSVCR120_nan(const char *tagp)
3282 /* Windows ignores input (MSDN) */
3283 return NAN;
3286 /*********************************************************************
3287 * nanf (MSVCR120.@)
3289 float CDECL MSVCR120_nanf(const char *tagp)
3291 return NAN;
3294 /*********************************************************************
3295 * _except1 (MSVCR120.@)
3296 * TODO:
3297 * - find meaning of ignored cw and operation bits
3298 * - unk parameter
3300 double CDECL _except1(DWORD fpe, _FP_OPERATION_CODE op, double arg, double res, DWORD cw, void *unk)
3302 ULONG_PTR exception_arg;
3303 DWORD exception = 0;
3304 MSVCRT_fenv_t env;
3305 DWORD fpword = 0;
3306 WORD operation;
3308 TRACE("(%x %x %lf %lf %x %p)\n", fpe, op, arg, res, cw, unk);
3310 #ifdef _WIN64
3311 cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
3312 #endif
3313 operation = op << 5;
3314 exception_arg = (ULONG_PTR)&operation;
3316 MSVCRT_fegetenv(&env);
3318 if (fpe & 0x1) { /* overflow */
3319 if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
3320 /* 32-bit version also sets SW_INEXACT here */
3321 env.status |= MSVCRT__SW_OVERFLOW;
3322 if (fpe & 0x10) env.status |= MSVCRT__SW_INEXACT;
3323 res = signbit(res) ? -INFINITY : INFINITY;
3324 } else {
3325 exception = EXCEPTION_FLT_OVERFLOW;
3327 } else if (fpe & 0x2) { /* underflow */
3328 if ((fpe == 0x2 && (cw & 0x10)) || (fpe==0x12 && (cw & 0x30))) {
3329 env.status |= MSVCRT__SW_UNDERFLOW;
3330 if (fpe & 0x10) env.status |= MSVCRT__SW_INEXACT;
3331 res = signbit(res) ? -0.0 : 0.0;
3332 } else {
3333 exception = EXCEPTION_FLT_UNDERFLOW;
3335 } else if (fpe & 0x4) { /* zerodivide */
3336 if ((fpe == 0x4 && (cw & 0x4)) || (fpe==0x14 && (cw & 0x24))) {
3337 env.status |= MSVCRT__SW_ZERODIVIDE;
3338 if (fpe & 0x10) env.status |= MSVCRT__SW_INEXACT;
3339 } else {
3340 exception = EXCEPTION_FLT_DIVIDE_BY_ZERO;
3342 } else if (fpe & 0x8) { /* invalid */
3343 if (fpe == 0x8 && (cw & 0x1)) {
3344 env.status |= MSVCRT__SW_INVALID;
3345 } else {
3346 exception = EXCEPTION_FLT_INVALID_OPERATION;
3348 } else if (fpe & 0x10) { /* inexact */
3349 if (fpe == 0x10 && (cw & 0x20)) {
3350 env.status |= MSVCRT__SW_INEXACT;
3351 } else {
3352 exception = EXCEPTION_FLT_INEXACT_RESULT;
3356 if (exception)
3357 env.status = 0;
3358 MSVCRT_fesetenv(&env);
3359 if (exception)
3360 RaiseException(exception, 0, 1, &exception_arg);
3362 if (cw & 0x1) fpword |= MSVCRT__EM_INVALID;
3363 if (cw & 0x2) fpword |= MSVCRT__EM_DENORMAL;
3364 if (cw & 0x4) fpword |= MSVCRT__EM_ZERODIVIDE;
3365 if (cw & 0x8) fpword |= MSVCRT__EM_OVERFLOW;
3366 if (cw & 0x10) fpword |= MSVCRT__EM_UNDERFLOW;
3367 if (cw & 0x20) fpword |= MSVCRT__EM_INEXACT;
3368 switch (cw & 0xc00)
3370 case 0xc00: fpword |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
3371 case 0x800: fpword |= MSVCRT__RC_UP; break;
3372 case 0x400: fpword |= MSVCRT__RC_DOWN; break;
3374 switch (cw & 0x300)
3376 case 0x0: fpword |= MSVCRT__PC_24; break;
3377 case 0x200: fpword |= MSVCRT__PC_53; break;
3378 case 0x300: fpword |= MSVCRT__PC_64; break;
3380 if (cw & 0x1000) fpword |= MSVCRT__IC_AFFINE;
3381 _control87(fpword, 0xffffffff);
3383 return res;
3386 _Dcomplex* CDECL MSVCR120__Cbuild(_Dcomplex *ret, double r, double i)
3388 ret->x = r;
3389 ret->y = i;
3390 return ret;
3393 double CDECL MSVCR120_creal(_Dcomplex z)
3395 return z.x;
3398 #endif /* _MSVCR_VER>=120 */