winmm: Avoid explicitly casting the pointer returned from Heap(Re)Alloc.
[wine.git] / dlls / msvcrt / math.c
bloba62705bc8f416daa420e8f4617b931b0210402cb
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
21 * For functions copied from musl libc (http://musl.libc.org/):
22 * ====================================================
23 * Copyright 2005-2020 Rich Felker, et al.
25 * Permission is hereby granted, free of charge, to any person obtaining
26 * a copy of this software and associated documentation files (the
27 * "Software"), to deal in the Software without restriction, including
28 * without limitation the rights to use, copy, modify, merge, publish,
29 * distribute, sublicense, and/or sell copies of the Software, and to
30 * permit persons to whom the Software is furnished to do so, subject to
31 * the following conditions:
33 * The above copyright notice and this permission notice shall be
34 * included in all copies or substantial portions of the Software.
35 * ====================================================
38 #include <assert.h>
39 #include <complex.h>
40 #include <stdio.h>
41 #include <fenv.h>
42 #include <fpieee.h>
43 #include <limits.h>
44 #include <locale.h>
45 #include <math.h>
47 #include "msvcrt.h"
48 #include "winternl.h"
50 #include "wine/asm.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
55 #undef div
56 #undef ldiv
58 #define _DOMAIN 1 /* domain error in argument */
59 #define _SING 2 /* singularity */
60 #define _OVERFLOW 3 /* range overflow */
61 #define _UNDERFLOW 4 /* range underflow */
63 typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *);
65 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
67 BOOL sse2_supported;
68 static BOOL sse2_enabled;
70 void msvcrt_init_math( void *module )
72 sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
73 #if _MSVCR_VER <=71
74 sse2_enabled = FALSE;
75 #else
76 sse2_enabled = sse2_supported;
77 #endif
80 #if defined(__i386__) || defined(__x86_64__)
81 static inline double ret_nan( BOOL update_sw )
83 double x = 1.0;
84 if (!update_sw) return -NAN;
85 return (x - x) / (x - x);
87 #endif
89 #define SET_X87_CW(MASK) \
90 "subl $4, %esp\n\t" \
91 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
92 "fnstcw (%esp)\n\t" \
93 "movw (%esp), %ax\n\t" \
94 "movw %ax, 2(%esp)\n\t" \
95 "testw $" #MASK ", %ax\n\t" \
96 "jz 1f\n\t" \
97 "andw $~" #MASK ", %ax\n\t" \
98 "movw %ax, 2(%esp)\n\t" \
99 "fldcw 2(%esp)\n\t" \
100 "1:\n\t"
102 #define RESET_X87_CW \
103 "movw (%esp), %ax\n\t" \
104 "cmpw %ax, 2(%esp)\n\t" \
105 "je 1f\n\t" \
106 "fstpl 8(%esp)\n\t" \
107 "fldcw (%esp)\n\t" \
108 "fldl 8(%esp)\n\t" \
109 "fwait\n\t" \
110 "1:\n\t" \
111 "addl $4, %esp\n\t" \
112 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
114 /*********************************************************************
115 * _matherr (CRTDLL.@)
117 int CDECL _matherr(struct _exception *e)
119 return 0;
123 double math_error(int type, const char *name, double arg1, double arg2, double retval)
125 struct _exception exception = {type, (char *)name, arg1, arg2, retval};
127 TRACE("(%d, %s, %g, %g, %g)\n", type, debugstr_a(name), arg1, arg2, retval);
129 if (MSVCRT_default_matherr_func && MSVCRT_default_matherr_func(&exception))
130 return exception.retval;
132 switch (type)
134 case 0:
135 /* don't set errno */
136 break;
137 case _DOMAIN:
138 *_errno() = EDOM;
139 break;
140 case _SING:
141 case _OVERFLOW:
142 *_errno() = ERANGE;
143 break;
144 case _UNDERFLOW:
145 /* don't set errno */
146 break;
147 default:
148 ERR("Unhandled math error!\n");
151 return exception.retval;
154 /*********************************************************************
155 * __setusermatherr (MSVCRT.@)
157 void CDECL __setusermatherr(MSVCRT_matherr_func func)
159 MSVCRT_default_matherr_func = func;
160 TRACE("new matherr handler %p\n", func);
163 /*********************************************************************
164 * _set_SSE2_enable (MSVCRT.@)
166 int CDECL _set_SSE2_enable(int flag)
168 sse2_enabled = flag && sse2_supported;
169 return sse2_enabled;
172 #if defined(_WIN64)
173 # if _MSVCR_VER>=140
174 /*********************************************************************
175 * _get_FMA3_enable (UCRTBASE.@)
177 int CDECL _get_FMA3_enable(void)
179 FIXME("() stub\n");
180 return 0;
182 # endif
184 # if _MSVCR_VER>=120
185 /*********************************************************************
186 * _set_FMA3_enable (MSVCR120.@)
188 int CDECL _set_FMA3_enable(int flag)
190 FIXME("(%x) stub\n", flag);
191 return 0;
193 # endif
194 #endif
196 #if !defined(__i386__) || _MSVCR_VER>=120
198 /*********************************************************************
199 * _chgsignf (MSVCRT.@)
201 float CDECL _chgsignf( float num )
203 union { float f; UINT32 i; } u = { num };
204 u.i ^= 0x80000000;
205 return u.f;
208 #endif
210 #ifndef __i386__
212 /*********************************************************************
213 * _fpclassf (MSVCRT.@)
215 int CDECL _fpclassf( float num )
217 union { float f; UINT32 i; } u = { num };
218 int e = u.i >> 23 & 0xff;
219 int s = u.i >> 31;
221 switch (e)
223 case 0:
224 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
225 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
226 case 0xff:
227 if (u.i << 9) return ((u.i >> 22) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
228 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
229 default:
230 return s ? _FPCLASS_NN : _FPCLASS_PN;
234 /*********************************************************************
235 * _finitef (MSVCRT.@)
237 int CDECL _finitef( float num )
239 union { float f; UINT32 i; } u = { num };
240 return (u.i & 0x7fffffff) < 0x7f800000;
243 /*********************************************************************
244 * _isnanf (MSVCRT.@)
246 int CDECL _isnanf( float num )
248 union { float f; UINT32 i; } u = { num };
249 return (u.i & 0x7fffffff) > 0x7f800000;
252 /*********************************************************************
253 * atanf (MSVCRT.@)
255 #if _MSVCR_VER == 0 /* other versions call atanf() directly */
256 float CDECL MSVCRT_atanf( float x )
258 if (isnan(x)) return math_error(_DOMAIN, "atanf", x, 0, x);
259 return atanf( x );
261 #endif
263 #ifdef __x86_64__
264 extern short CDECL _fdclass(float x);
266 static BOOL sqrtf_validate( float *x )
268 short c = _fdclass(*x);
270 if (c == FP_ZERO) return FALSE;
271 if (c == FP_NAN) return FALSE;
272 if (signbit(*x))
274 *x = math_error(_DOMAIN, "sqrtf", *x, 0, ret_nan(TRUE));
275 return FALSE;
277 if (c == FP_INFINITE) return FALSE;
278 return TRUE;
281 float CDECL sse2_sqrtf(float);
282 __ASM_GLOBAL_FUNC( sse2_sqrtf,
283 "sqrtss %xmm0, %xmm0\n\t"
284 "ret" )
285 #endif
287 /*********************************************************************
288 * sqrtf (MSVCRT.@)
290 float CDECL MSVCRT_sqrtf( float x )
292 #ifdef __x86_64__
293 if (!sqrtf_validate(&x))
294 return x;
296 return sse2_sqrtf(x);
297 #else
298 return sqrtf( x );
299 #endif
302 /*********************************************************************
303 * tanhf (MSVCRT.@)
305 #if _MSVCR_VER < 140 /* other versions call tanhf() directly */
306 float CDECL MSVCRT_tanhf( float x )
308 if (isnan( x ))
310 *(UINT32*)&x |= 0x400000;
311 return math_error(_DOMAIN, "tanhf", x, 0, x);
313 return tanhf( x );
315 #endif
317 #endif
319 /*********************************************************************
320 * asin (MSVCRT.@)
322 #ifdef __i386__
323 double CDECL x87_asin(double);
324 __ASM_GLOBAL_FUNC( x87_asin,
325 "fldl 4(%esp)\n\t"
326 SET_X87_CW(~0x37f)
327 "fld %st\n\t"
328 "fld1\n\t"
329 "fsubp\n\t"
330 "fld1\n\t"
331 "fadd %st(2)\n\t"
332 "fmulp\n\t"
333 "fsqrt\n\t"
334 "fpatan\n\t"
335 RESET_X87_CW
336 "ret" )
337 #endif
339 double CDECL MSVCRT_asin( double x )
341 #ifdef __i386__
342 unsigned int x87_cw, sse2_cw;
343 unsigned int hx = *(ULONGLONG*)&x >> 32;
344 unsigned int ix = hx & 0x7fffffff;
346 if (isnan(x)) return math_error(_DOMAIN, "asin", x, 0, x);
348 /* |x| < 1 */
349 if (ix < 0x3ff00000)
351 __control87_2(0, 0, &x87_cw, &sse2_cw);
352 if (!sse2_enabled || (x87_cw & _MCW_EM) != _MCW_EM
353 || (sse2_cw & (_MCW_EM | _MCW_RC)) != _MCW_EM)
354 return x87_asin(x);
356 #else
357 if (isnan(x)) return x;
358 #endif
360 return asin( x );
363 /*********************************************************************
364 * atan (MSVCRT.@)
366 #if _MSVCR_VER == 0 /* other versions call atan() directly */
367 double CDECL MSVCRT_atan( double x )
369 if (isnan(x)) return math_error(_DOMAIN, "atan", x, 0, x);
370 return atan( x );
372 #endif
374 /*********************************************************************
375 * exp (MSVCRT.@)
377 #if _MSVCR_VER == 0 /* other versions call exp() directly */
378 double CDECL MSVCRT_exp( double x )
380 if (isnan( x )) return math_error(_DOMAIN, "exp", x, 0, 1.0 + x);
381 return exp( x );
383 #endif
385 #if defined(__x86_64__) || defined(__i386__)
386 extern short CDECL _dclass(double x);
388 static BOOL sqrt_validate( double *x, BOOL update_sw )
390 short c = _dclass(*x);
392 if (c == FP_ZERO) return FALSE;
393 if (c == FP_NAN)
395 #ifdef __i386__
396 if (update_sw)
397 *x = math_error(_DOMAIN, "sqrt", *x, 0, *x);
398 #else
399 /* set signaling bit */
400 *(ULONGLONG*)x |= 0x8000000000000ULL;
401 #endif
402 return FALSE;
404 if (signbit(*x))
406 *x = math_error(_DOMAIN, "sqrt", *x, 0, ret_nan(update_sw));
407 return FALSE;
409 if (c == FP_INFINITE) return FALSE;
410 return TRUE;
413 double CDECL sse2_sqrt(double);
414 __ASM_GLOBAL_FUNC( sse2_sqrt,
415 "sqrtsd %xmm0, %xmm0\n\t"
416 "ret" )
417 #endif
419 #ifdef __i386__
420 double CDECL x87_sqrt(double);
421 __ASM_GLOBAL_FUNC( x87_sqrt,
422 "fldl 4(%esp)\n\t"
423 SET_X87_CW(0xc00)
424 "fsqrt\n\t"
425 RESET_X87_CW
426 "ret" )
427 #endif
429 /*********************************************************************
430 * sqrt (MSVCRT.@)
432 double CDECL MSVCRT_sqrt( double x )
434 #ifdef __x86_64__
435 if (!sqrt_validate(&x, TRUE))
436 return x;
438 return sse2_sqrt(x);
439 #elif defined( __i386__ )
440 if (!sqrt_validate(&x, TRUE))
441 return x;
443 return x87_sqrt(x);
444 #else
445 return sqrt( x );
446 #endif
449 /*********************************************************************
450 * tanh (MSVCRT.@)
452 #if _MSVCR_VER < 140 /* other versions call tanh() directly */
453 double CDECL MSVCRT_tanh( double x )
455 if (isnan( x ))
457 *(UINT64*)&x |= 0x0008000000000000ULL;
458 return math_error(_DOMAIN, "tanh", x, 0, x);
460 return tanh( x );
462 #endif
464 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
466 #define CREATE_FPU_FUNC1(name, call) \
467 __ASM_GLOBAL_FUNC(name, \
468 "pushl %ebp\n\t" \
469 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
470 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
471 "movl %esp, %ebp\n\t" \
472 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
473 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
474 "fstpl (%esp)\n\t" /* store function argument */ \
475 "fwait\n\t" \
476 "movl $1, %ecx\n\t" /* empty FPU stack */ \
477 "1:\n\t" \
478 "fxam\n\t" \
479 "fstsw %ax\n\t" \
480 "and $0x4500, %ax\n\t" \
481 "cmp $0x4100, %ax\n\t" \
482 "je 2f\n\t" \
483 "fstpl (%esp,%ecx,8)\n\t" \
484 "fwait\n\t" \
485 "incl %ecx\n\t" \
486 "jmp 1b\n\t" \
487 "2:\n\t" \
488 "movl %ecx, -4(%ebp)\n\t" \
489 "call " __ASM_NAME( #call ) "\n\t" \
490 "movl -4(%ebp), %ecx\n\t" \
491 "fstpl (%esp)\n\t" /* save result */ \
492 "3:\n\t" /* restore FPU stack */ \
493 "decl %ecx\n\t" \
494 "fldl (%esp,%ecx,8)\n\t" \
495 "cmpl $0, %ecx\n\t" \
496 "jne 3b\n\t" \
497 "leave\n\t" \
498 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
499 __ASM_CFI(".cfi_same_value %ebp\n\t") \
500 "ret")
502 #define CREATE_FPU_FUNC2(name, call) \
503 __ASM_GLOBAL_FUNC(name, \
504 "pushl %ebp\n\t" \
505 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
506 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") \
507 "movl %esp, %ebp\n\t" \
508 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") \
509 "subl $68, %esp\n\t" /* sizeof(double)*8 + sizeof(int) */ \
510 "fstpl 8(%esp)\n\t" /* store function argument */ \
511 "fwait\n\t" \
512 "fstpl (%esp)\n\t" \
513 "fwait\n\t" \
514 "movl $2, %ecx\n\t" /* empty FPU stack */ \
515 "1:\n\t" \
516 "fxam\n\t" \
517 "fstsw %ax\n\t" \
518 "and $0x4500, %ax\n\t" \
519 "cmp $0x4100, %ax\n\t" \
520 "je 2f\n\t" \
521 "fstpl (%esp,%ecx,8)\n\t" \
522 "fwait\n\t" \
523 "incl %ecx\n\t" \
524 "jmp 1b\n\t" \
525 "2:\n\t" \
526 "movl %ecx, -4(%ebp)\n\t" \
527 "call " __ASM_NAME( #call ) "\n\t" \
528 "movl -4(%ebp), %ecx\n\t" \
529 "fstpl 8(%esp)\n\t" /* save result */ \
530 "3:\n\t" /* restore FPU stack */ \
531 "decl %ecx\n\t" \
532 "fldl (%esp,%ecx,8)\n\t" \
533 "cmpl $1, %ecx\n\t" \
534 "jne 3b\n\t" \
535 "leave\n\t" \
536 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") \
537 __ASM_CFI(".cfi_same_value %ebp\n\t") \
538 "ret")
540 CREATE_FPU_FUNC1(_CIacos, acos)
541 CREATE_FPU_FUNC1(_CIasin, asin)
542 CREATE_FPU_FUNC1(_CIatan, atan)
543 CREATE_FPU_FUNC2(_CIatan2, atan2)
544 CREATE_FPU_FUNC1(_CIcos, cos)
545 CREATE_FPU_FUNC1(_CIcosh, cosh)
546 CREATE_FPU_FUNC1(_CIexp, exp)
547 CREATE_FPU_FUNC2(_CIfmod, fmod)
548 CREATE_FPU_FUNC1(_CIlog, log)
549 CREATE_FPU_FUNC1(_CIlog10, log10)
550 CREATE_FPU_FUNC2(_CIpow, pow)
551 CREATE_FPU_FUNC1(_CIsin, sin)
552 CREATE_FPU_FUNC1(_CIsinh, sinh)
553 CREATE_FPU_FUNC1(_CIsqrt, sqrt)
554 CREATE_FPU_FUNC1(_CItan, tan)
555 CREATE_FPU_FUNC1(_CItanh, tanh)
557 __ASM_GLOBAL_FUNC(_ftol,
558 "pushl %ebp\n\t"
559 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
560 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
561 "movl %esp, %ebp\n\t"
562 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
563 "subl $12, %esp\n\t" /* sizeof(LONGLONG) + 2*sizeof(WORD) */
564 "fnstcw (%esp)\n\t"
565 "mov (%esp), %ax\n\t"
566 "or $0xc00, %ax\n\t"
567 "mov %ax, 2(%esp)\n\t"
568 "fldcw 2(%esp)\n\t"
569 "fistpq 4(%esp)\n\t"
570 "fldcw (%esp)\n\t"
571 "movl 4(%esp), %eax\n\t"
572 "movl 8(%esp), %edx\n\t"
573 "leave\n\t"
574 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
575 __ASM_CFI(".cfi_same_value %ebp\n\t")
576 "ret")
578 #endif /* (defined(__GNUC__) || defined(__clang__)) && defined(__i386__) */
580 /*********************************************************************
581 * _fpclass (MSVCRT.@)
583 int CDECL _fpclass(double num)
585 union { double f; UINT64 i; } u = { num };
586 int e = u.i >> 52 & 0x7ff;
587 int s = u.i >> 63;
589 switch (e)
591 case 0:
592 if (u.i << 1) return s ? _FPCLASS_ND : _FPCLASS_PD;
593 return s ? _FPCLASS_NZ : _FPCLASS_PZ;
594 case 0x7ff:
595 if (u.i << 12) return ((u.i >> 51) & 1) ? _FPCLASS_QNAN : _FPCLASS_SNAN;
596 return s ? _FPCLASS_NINF : _FPCLASS_PINF;
597 default:
598 return s ? _FPCLASS_NN : _FPCLASS_PN;
602 /*********************************************************************
603 * _rotl (MSVCRT.@)
605 unsigned int CDECL MSVCRT__rotl(unsigned int num, int shift)
607 shift &= 31;
608 return (num << shift) | (num >> (32-shift));
611 /*********************************************************************
612 * _lrotl (MSVCRT.@)
614 __msvcrt_ulong CDECL MSVCRT__lrotl(__msvcrt_ulong num, int shift)
616 shift &= 0x1f;
617 return (num << shift) | (num >> (32-shift));
620 /*********************************************************************
621 * _lrotr (MSVCRT.@)
623 __msvcrt_ulong CDECL MSVCRT__lrotr(__msvcrt_ulong num, int shift)
625 shift &= 0x1f;
626 return (num >> shift) | (num << (32-shift));
629 /*********************************************************************
630 * _rotr (MSVCRT.@)
632 unsigned int CDECL MSVCRT__rotr(unsigned int num, int shift)
634 shift &= 0x1f;
635 return (num >> shift) | (num << (32-shift));
638 /*********************************************************************
639 * _rotl64 (MSVCRT.@)
641 unsigned __int64 CDECL MSVCRT__rotl64(unsigned __int64 num, int shift)
643 shift &= 63;
644 return (num << shift) | (num >> (64-shift));
647 /*********************************************************************
648 * _rotr64 (MSVCRT.@)
650 unsigned __int64 CDECL MSVCRT__rotr64(unsigned __int64 num, int shift)
652 shift &= 63;
653 return (num >> shift) | (num << (64-shift));
656 /*********************************************************************
657 * abs (MSVCRT.@)
659 int CDECL abs( int n )
661 return n >= 0 ? n : -n;
664 /*********************************************************************
665 * labs (MSVCRT.@)
667 __msvcrt_long CDECL labs( __msvcrt_long n )
669 return n >= 0 ? n : -n;
672 #if _MSVCR_VER>=100
673 /*********************************************************************
674 * llabs (MSVCR100.@)
676 __int64 CDECL llabs( __int64 n )
678 return n >= 0 ? n : -n;
680 #endif
682 #if _MSVCR_VER>=120
683 /*********************************************************************
684 * imaxabs (MSVCR120.@)
686 intmax_t CDECL imaxabs( intmax_t n )
688 return n >= 0 ? n : -n;
690 #endif
692 /*********************************************************************
693 * _abs64 (MSVCRT.@)
695 __int64 CDECL _abs64( __int64 n )
697 return n >= 0 ? n : -n;
700 #if defined(__i386__) || defined(__x86_64__)
701 static void _setfp_sse( unsigned int *cw, unsigned int cw_mask,
702 unsigned int *sw, unsigned int sw_mask )
704 #if defined(__GNUC__) || defined(__clang__)
705 unsigned long old_fpword, fpword;
706 unsigned int flags;
708 __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
709 old_fpword = fpword;
711 cw_mask &= _MCW_EM | _MCW_RC | _MCW_DN;
712 sw_mask &= _MCW_EM;
714 if (sw)
716 flags = 0;
717 if (fpword & 0x1) flags |= _SW_INVALID;
718 if (fpword & 0x2) flags |= _SW_DENORMAL;
719 if (fpword & 0x4) flags |= _SW_ZERODIVIDE;
720 if (fpword & 0x8) flags |= _SW_OVERFLOW;
721 if (fpword & 0x10) flags |= _SW_UNDERFLOW;
722 if (fpword & 0x20) flags |= _SW_INEXACT;
724 *sw = (flags & ~sw_mask) | (*sw & sw_mask);
725 TRACE("sse2 update sw %08x to %08x\n", flags, *sw);
726 fpword &= ~0x3f;
727 if (*sw & _SW_INVALID) fpword |= 0x1;
728 if (*sw & _SW_DENORMAL) fpword |= 0x2;
729 if (*sw & _SW_ZERODIVIDE) fpword |= 0x4;
730 if (*sw & _SW_OVERFLOW) fpword |= 0x8;
731 if (*sw & _SW_UNDERFLOW) fpword |= 0x10;
732 if (*sw & _SW_INEXACT) fpword |= 0x20;
733 *sw = flags;
736 if (cw)
738 flags = 0;
739 if (fpword & 0x80) flags |= _EM_INVALID;
740 if (fpword & 0x100) flags |= _EM_DENORMAL;
741 if (fpword & 0x200) flags |= _EM_ZERODIVIDE;
742 if (fpword & 0x400) flags |= _EM_OVERFLOW;
743 if (fpword & 0x800) flags |= _EM_UNDERFLOW;
744 if (fpword & 0x1000) flags |= _EM_INEXACT;
745 switch (fpword & 0x6000)
747 case 0x6000: flags |= _RC_UP|_RC_DOWN; break;
748 case 0x4000: flags |= _RC_UP; break;
749 case 0x2000: flags |= _RC_DOWN; break;
751 switch (fpword & 0x8040)
753 case 0x0040: flags |= _DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
754 case 0x8000: flags |= _DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
755 case 0x8040: flags |= _DN_FLUSH; break;
758 *cw = (flags & ~cw_mask) | (*cw & cw_mask);
759 TRACE("sse2 update cw %08x to %08x\n", flags, *cw);
760 fpword &= ~0xffc0;
761 if (*cw & _EM_INVALID) fpword |= 0x80;
762 if (*cw & _EM_DENORMAL) fpword |= 0x100;
763 if (*cw & _EM_ZERODIVIDE) fpword |= 0x200;
764 if (*cw & _EM_OVERFLOW) fpword |= 0x400;
765 if (*cw & _EM_UNDERFLOW) fpword |= 0x800;
766 if (*cw & _EM_INEXACT) fpword |= 0x1000;
767 switch (*cw & _MCW_RC)
769 case _RC_UP|_RC_DOWN: fpword |= 0x6000; break;
770 case _RC_UP: fpword |= 0x4000; break;
771 case _RC_DOWN: fpword |= 0x2000; break;
773 switch (*cw & _MCW_DN)
775 case _DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
776 case _DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
777 case _DN_FLUSH: fpword |= 0x8040; break;
780 /* clear status word if anything changes */
781 if (fpword != old_fpword && !sw)
783 TRACE("sse2 clear status word\n");
784 fpword &= ~0x3f;
788 if (fpword != old_fpword)
789 __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
790 #else
791 FIXME("not implemented\n");
792 if (cw) *cw = 0;
793 if (sw) *sw = 0;
794 #endif
796 #endif
798 static void _setfp( unsigned int *cw, unsigned int cw_mask,
799 unsigned int *sw, unsigned int sw_mask )
801 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
802 unsigned long oldcw = 0, newcw = 0;
803 unsigned long oldsw = 0, newsw = 0;
804 unsigned int flags;
806 cw_mask &= _MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC;
807 sw_mask &= _MCW_EM;
809 if (sw)
811 __asm__ __volatile__( "fstsw %0" : "=m" (newsw) );
812 oldsw = newsw;
814 flags = 0;
815 if (newsw & 0x1) flags |= _SW_INVALID;
816 if (newsw & 0x2) flags |= _SW_DENORMAL;
817 if (newsw & 0x4) flags |= _SW_ZERODIVIDE;
818 if (newsw & 0x8) flags |= _SW_OVERFLOW;
819 if (newsw & 0x10) flags |= _SW_UNDERFLOW;
820 if (newsw & 0x20) flags |= _SW_INEXACT;
822 *sw = (flags & ~sw_mask) | (*sw & sw_mask);
823 TRACE("x86 update sw %08x to %08x\n", flags, *sw);
824 newsw &= ~0x3f;
825 if (*sw & _SW_INVALID) newsw |= 0x1;
826 if (*sw & _SW_DENORMAL) newsw |= 0x2;
827 if (*sw & _SW_ZERODIVIDE) newsw |= 0x4;
828 if (*sw & _SW_OVERFLOW) newsw |= 0x8;
829 if (*sw & _SW_UNDERFLOW) newsw |= 0x10;
830 if (*sw & _SW_INEXACT) newsw |= 0x20;
831 *sw = flags;
834 if (cw)
836 __asm__ __volatile__( "fstcw %0" : "=m" (newcw) );
837 oldcw = newcw;
839 flags = 0;
840 if (newcw & 0x1) flags |= _EM_INVALID;
841 if (newcw & 0x2) flags |= _EM_DENORMAL;
842 if (newcw & 0x4) flags |= _EM_ZERODIVIDE;
843 if (newcw & 0x8) flags |= _EM_OVERFLOW;
844 if (newcw & 0x10) flags |= _EM_UNDERFLOW;
845 if (newcw & 0x20) flags |= _EM_INEXACT;
846 switch (newcw & 0xc00)
848 case 0xc00: flags |= _RC_UP|_RC_DOWN; break;
849 case 0x800: flags |= _RC_UP; break;
850 case 0x400: flags |= _RC_DOWN; break;
852 switch (newcw & 0x300)
854 case 0x0: flags |= _PC_24; break;
855 case 0x200: flags |= _PC_53; break;
856 case 0x300: flags |= _PC_64; break;
858 if (newcw & 0x1000) flags |= _IC_AFFINE;
860 *cw = (flags & ~cw_mask) | (*cw & cw_mask);
861 TRACE("x86 update cw %08x to %08x\n", flags, *cw);
862 newcw &= ~0x1f3f;
863 if (*cw & _EM_INVALID) newcw |= 0x1;
864 if (*cw & _EM_DENORMAL) newcw |= 0x2;
865 if (*cw & _EM_ZERODIVIDE) newcw |= 0x4;
866 if (*cw & _EM_OVERFLOW) newcw |= 0x8;
867 if (*cw & _EM_UNDERFLOW) newcw |= 0x10;
868 if (*cw & _EM_INEXACT) newcw |= 0x20;
869 switch (*cw & _MCW_RC)
871 case _RC_UP|_RC_DOWN: newcw |= 0xc00; break;
872 case _RC_UP: newcw |= 0x800; break;
873 case _RC_DOWN: newcw |= 0x400; break;
875 switch (*cw & _MCW_PC)
877 case _PC_64: newcw |= 0x300; break;
878 case _PC_53: newcw |= 0x200; break;
879 case _PC_24: newcw |= 0x0; break;
881 if (*cw & _IC_AFFINE) newcw |= 0x1000;
884 if (oldsw != newsw && (newsw & 0x3f))
886 struct {
887 WORD control_word;
888 WORD unused1;
889 WORD status_word;
890 WORD unused2;
891 WORD tag_word;
892 WORD unused3;
893 DWORD instruction_pointer;
894 WORD code_segment;
895 WORD unused4;
896 DWORD operand_addr;
897 WORD data_segment;
898 WORD unused5;
899 } fenv;
901 assert(cw);
903 __asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
904 fenv.control_word = newcw;
905 fenv.status_word = newsw;
906 __asm__ __volatile__( "fldenv %0" : : "m" (fenv) : "st", "st(1)",
907 "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" );
908 return;
911 if (oldsw != newsw)
912 __asm__ __volatile__( "fnclex" );
913 if (oldcw != newcw)
914 __asm__ __volatile__( "fldcw %0" : : "m" (newcw) );
915 #elif defined(__x86_64__)
916 _setfp_sse(cw, cw_mask, sw, sw_mask);
917 #elif defined(__aarch64__)
918 ULONG_PTR old_fpsr = 0, fpsr = 0, old_fpcr = 0, fpcr = 0;
919 unsigned int flags;
921 cw_mask &= _MCW_EM | _MCW_RC;
922 sw_mask &= _MCW_EM;
924 if (sw)
926 __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) );
927 old_fpsr = fpsr;
929 flags = 0;
930 if (fpsr & 0x1) flags |= _SW_INVALID;
931 if (fpsr & 0x2) flags |= _SW_ZERODIVIDE;
932 if (fpsr & 0x4) flags |= _SW_OVERFLOW;
933 if (fpsr & 0x8) flags |= _SW_UNDERFLOW;
934 if (fpsr & 0x10) flags |= _SW_INEXACT;
935 if (fpsr & 0x80) flags |= _SW_DENORMAL;
937 *sw = (flags & ~sw_mask) | (*sw & sw_mask);
938 TRACE("aarch64 update sw %08x to %08x\n", flags, *sw);
939 fpsr &= ~0x9f;
940 if (*sw & _SW_INVALID) fpsr |= 0x1;
941 if (*sw & _SW_ZERODIVIDE) fpsr |= 0x2;
942 if (*sw & _SW_OVERFLOW) fpsr |= 0x4;
943 if (*sw & _SW_UNDERFLOW) fpsr |= 0x8;
944 if (*sw & _SW_INEXACT) fpsr |= 0x10;
945 if (*sw & _SW_DENORMAL) fpsr |= 0x80;
946 *sw = flags;
949 if (cw)
951 __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) );
952 old_fpcr = fpcr;
954 flags = 0;
955 if (!(fpcr & 0x100)) flags |= _EM_INVALID;
956 if (!(fpcr & 0x200)) flags |= _EM_ZERODIVIDE;
957 if (!(fpcr & 0x400)) flags |= _EM_OVERFLOW;
958 if (!(fpcr & 0x800)) flags |= _EM_UNDERFLOW;
959 if (!(fpcr & 0x1000)) flags |= _EM_INEXACT;
960 if (!(fpcr & 0x8000)) flags |= _EM_DENORMAL;
961 switch (fpcr & 0xc00000)
963 case 0x400000: flags |= _RC_UP; break;
964 case 0x800000: flags |= _RC_DOWN; break;
965 case 0xc00000: flags |= _RC_CHOP; break;
968 *cw = (flags & ~cw_mask) | (*cw & cw_mask);
969 TRACE("aarch64 update cw %08x to %08x\n", flags, *cw);
970 fpcr &= ~0xc09f00ul;
971 if (!(*cw & _EM_INVALID)) fpcr |= 0x100;
972 if (!(*cw & _EM_ZERODIVIDE)) fpcr |= 0x200;
973 if (!(*cw & _EM_OVERFLOW)) fpcr |= 0x400;
974 if (!(*cw & _EM_UNDERFLOW)) fpcr |= 0x800;
975 if (!(*cw & _EM_INEXACT)) fpcr |= 0x1000;
976 if (!(*cw & _EM_DENORMAL)) fpcr |= 0x8000;
977 switch (*cw & _MCW_RC)
979 case _RC_CHOP: fpcr |= 0xc00000; break;
980 case _RC_UP: fpcr |= 0x400000; break;
981 case _RC_DOWN: fpcr |= 0x800000; break;
985 /* mask exceptions if needed */
986 if (old_fpcr != fpcr && ~(old_fpcr >> 8) & fpsr & 0x9f != fpsr & 0x9f)
988 ULONG_PTR mask = fpcr & ~0x9f00;
989 __asm__ __volatile__( "msr fpcr, %0" :: "r" (mask) );
992 if (old_fpsr != fpsr)
993 __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) );
994 if (old_fpcr != fpcr)
995 __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) );
996 #elif defined(__arm__) && !defined(__SOFTFP__)
997 DWORD old_fpscr, fpscr;
998 unsigned int flags;
1000 __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) );
1001 old_fpscr = fpscr;
1003 cw_mask &= _MCW_EM | _MCW_RC;
1004 sw_mask &= _MCW_EM;
1006 if (sw)
1008 flags = 0;
1009 if (fpscr & 0x1) flags |= _SW_INVALID;
1010 if (fpscr & 0x2) flags |= _SW_ZERODIVIDE;
1011 if (fpscr & 0x4) flags |= _SW_OVERFLOW;
1012 if (fpscr & 0x8) flags |= _SW_UNDERFLOW;
1013 if (fpscr & 0x10) flags |= _SW_INEXACT;
1014 if (fpscr & 0x80) flags |= _SW_DENORMAL;
1016 *sw = (flags & ~sw_mask) | (*sw & sw_mask);
1017 TRACE("arm update sw %08x to %08x\n", flags, *sw);
1018 fpscr &= ~0x9f;
1019 if (*sw & _SW_INVALID) fpscr |= 0x1;
1020 if (*sw & _SW_ZERODIVIDE) fpscr |= 0x2;
1021 if (*sw & _SW_OVERFLOW) fpscr |= 0x4;
1022 if (*sw & _SW_UNDERFLOW) fpscr |= 0x8;
1023 if (*sw & _SW_INEXACT) fpscr |= 0x10;
1024 if (*sw & _SW_DENORMAL) fpscr |= 0x80;
1025 *sw = flags;
1028 if (cw)
1030 flags = 0;
1031 if (!(fpscr & 0x100)) flags |= _EM_INVALID;
1032 if (!(fpscr & 0x200)) flags |= _EM_ZERODIVIDE;
1033 if (!(fpscr & 0x400)) flags |= _EM_OVERFLOW;
1034 if (!(fpscr & 0x800)) flags |= _EM_UNDERFLOW;
1035 if (!(fpscr & 0x1000)) flags |= _EM_INEXACT;
1036 if (!(fpscr & 0x8000)) flags |= _EM_DENORMAL;
1037 switch (fpscr & 0xc00000)
1039 case 0x400000: flags |= _RC_UP; break;
1040 case 0x800000: flags |= _RC_DOWN; break;
1041 case 0xc00000: flags |= _RC_CHOP; break;
1044 *cw = (flags & ~cw_mask) | (*cw & cw_mask);
1045 TRACE("arm update cw %08x to %08x\n", flags, *cw);
1046 fpscr &= ~0xc09f00ul;
1047 if (!(*cw & _EM_INVALID)) fpscr |= 0x100;
1048 if (!(*cw & _EM_ZERODIVIDE)) fpscr |= 0x200;
1049 if (!(*cw & _EM_OVERFLOW)) fpscr |= 0x400;
1050 if (!(*cw & _EM_UNDERFLOW)) fpscr |= 0x800;
1051 if (!(*cw & _EM_INEXACT)) fpscr |= 0x1000;
1052 if (!(*cw & _EM_DENORMAL)) fpscr |= 0x8000;
1053 switch (*cw & _MCW_RC)
1055 case _RC_CHOP: fpscr |= 0xc00000; break;
1056 case _RC_UP: fpscr |= 0x400000; break;
1057 case _RC_DOWN: fpscr |= 0x800000; break;
1061 if (old_fpscr != fpscr)
1062 __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) );
1063 #else
1064 FIXME("not implemented\n");
1065 if (cw) *cw = 0;
1066 if (sw) *sw = 0;
1067 #endif
1070 /**********************************************************************
1071 * _statusfp2 (MSVCR80.@)
1073 #if defined(__i386__)
1074 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
1076 if (x86_sw)
1077 _setfp(NULL, 0, x86_sw, 0);
1078 if (!sse2_sw) return;
1079 if (sse2_supported)
1080 _setfp_sse(NULL, 0, sse2_sw, 0);
1081 else *sse2_sw = 0;
1083 #endif
1085 /**********************************************************************
1086 * _statusfp (MSVCRT.@)
1088 unsigned int CDECL _statusfp(void)
1090 unsigned int flags = 0;
1091 #if defined(__i386__)
1092 unsigned int x86_sw, sse2_sw;
1094 _statusfp2( &x86_sw, &sse2_sw );
1095 /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
1096 flags = x86_sw | sse2_sw;
1097 #else
1098 _setfp(NULL, 0, &flags, 0);
1099 #endif
1100 return flags;
1103 /*********************************************************************
1104 * _clearfp (MSVCRT.@)
1106 unsigned int CDECL _clearfp(void)
1108 unsigned int flags = 0;
1109 #ifdef __i386__
1110 _setfp(NULL, 0, &flags, _MCW_EM);
1111 if (sse2_supported)
1113 unsigned int sse_sw = 0;
1115 _setfp_sse(NULL, 0, &sse_sw, _MCW_EM);
1116 flags |= sse_sw;
1118 #else
1119 _setfp(NULL, 0, &flags, _MCW_EM);
1120 #endif
1121 return flags;
1124 /*********************************************************************
1125 * __fpecode (MSVCRT.@)
1127 int * CDECL __fpecode(void)
1129 return &msvcrt_get_thread_data()->fpecode;
1132 /*********************************************************************
1133 * ldexp (MSVCRT.@)
1135 double CDECL ldexp(double num, int exp)
1137 double z = scalbn(num, exp);
1139 if (isfinite(num) && !isfinite(z))
1140 return math_error(_OVERFLOW, "ldexp", num, exp, z);
1141 if (num && isfinite(num) && !z)
1142 return math_error(_UNDERFLOW, "ldexp", num, exp, z);
1143 return z;
1146 /*********************************************************************
1147 * _cabs (MSVCRT.@)
1149 double CDECL _cabs(struct _complex num)
1151 return sqrt(num.x * num.x + num.y * num.y);
1154 /*********************************************************************
1155 * _chgsign (MSVCRT.@)
1157 double CDECL _chgsign(double num)
1159 union { double f; UINT64 i; } u = { num };
1160 u.i ^= 1ull << 63;
1161 return u.f;
1164 /*********************************************************************
1165 * __control87_2 (MSVCR80.@)
1167 * Not exported by native msvcrt, added in msvcr80.
1169 #ifdef __i386__
1170 int CDECL __control87_2( unsigned int newval, unsigned int mask,
1171 unsigned int *x86_cw, unsigned int *sse2_cw )
1173 if (x86_cw)
1175 *x86_cw = newval;
1176 _setfp(x86_cw, mask, NULL, 0);
1179 if (!sse2_cw) return 1;
1181 if (sse2_supported)
1183 *sse2_cw = newval;
1184 _setfp_sse(sse2_cw, mask, NULL, 0);
1186 else *sse2_cw = 0;
1188 return 1;
1190 #endif
1192 /*********************************************************************
1193 * _control87 (MSVCRT.@)
1195 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1197 unsigned int flags = 0;
1198 #if defined(__i386__) && (_MSVCR_VER == 0 || _MSVCR_VER >= 80)
1199 unsigned int sse2_cw;
1201 __control87_2( newval, mask, &flags, &sse2_cw );
1203 if (sse2_supported)
1205 if ((flags ^ sse2_cw) & (_MCW_EM | _MCW_RC)) flags |= _EM_AMBIGUOUS;
1206 flags |= sse2_cw;
1208 #else
1209 flags = newval;
1210 _setfp(&flags, mask, NULL, 0);
1211 #endif
1212 return flags;
1215 /*********************************************************************
1216 * _controlfp (MSVCRT.@)
1218 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
1220 return _control87( newval, mask & ~_EM_DENORMAL );
1223 /*********************************************************************
1224 * _set_controlfp (MSVCRT.@)
1226 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
1228 _controlfp( newval, mask );
1231 /*********************************************************************
1232 * _controlfp_s (MSVCRT.@)
1234 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
1236 static const unsigned int all_flags = (_MCW_EM | _MCW_IC | _MCW_RC |
1237 _MCW_PC | _MCW_DN);
1238 unsigned int val;
1240 if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
1242 if (cur) *cur = _controlfp( 0, 0 ); /* retrieve it anyway */
1243 return EINVAL;
1245 val = _controlfp( newval, mask );
1246 if (cur) *cur = val;
1247 return 0;
1250 #if _MSVCR_VER >= 140 && (defined(__i386__) || defined(__x86_64__))
1251 enum fenv_masks
1253 FENV_X_INVALID = 0x00100010,
1254 FENV_X_DENORMAL = 0x00200020,
1255 FENV_X_ZERODIVIDE = 0x00080008,
1256 FENV_X_OVERFLOW = 0x00040004,
1257 FENV_X_UNDERFLOW = 0x00020002,
1258 FENV_X_INEXACT = 0x00010001,
1259 FENV_X_AFFINE = 0x00004000,
1260 FENV_X_UP = 0x00800200,
1261 FENV_X_DOWN = 0x00400100,
1262 FENV_X_24 = 0x00002000,
1263 FENV_X_53 = 0x00001000,
1264 FENV_Y_INVALID = 0x10000010,
1265 FENV_Y_DENORMAL = 0x20000020,
1266 FENV_Y_ZERODIVIDE = 0x08000008,
1267 FENV_Y_OVERFLOW = 0x04000004,
1268 FENV_Y_UNDERFLOW = 0x02000002,
1269 FENV_Y_INEXACT = 0x01000001,
1270 FENV_Y_UP = 0x80000200,
1271 FENV_Y_DOWN = 0x40000100,
1272 FENV_Y_FLUSH = 0x00000400,
1273 FENV_Y_FLUSH_SAVE = 0x00000800
1276 /* encodes x87/sse control/status word in ulong */
1277 static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y)
1279 __msvcrt_ulong ret = 0;
1281 #ifdef __i386__
1282 if (x & _EM_INVALID) ret |= FENV_X_INVALID;
1283 if (x & _EM_DENORMAL) ret |= FENV_X_DENORMAL;
1284 if (x & _EM_ZERODIVIDE) ret |= FENV_X_ZERODIVIDE;
1285 if (x & _EM_OVERFLOW) ret |= FENV_X_OVERFLOW;
1286 if (x & _EM_UNDERFLOW) ret |= FENV_X_UNDERFLOW;
1287 if (x & _EM_INEXACT) ret |= FENV_X_INEXACT;
1288 if (x & _IC_AFFINE) ret |= FENV_X_AFFINE;
1289 if (x & _RC_UP) ret |= FENV_X_UP;
1290 if (x & _RC_DOWN) ret |= FENV_X_DOWN;
1291 if (x & _PC_24) ret |= FENV_X_24;
1292 if (x & _PC_53) ret |= FENV_X_53;
1293 #endif
1294 x &= ~(_MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC);
1296 if (y & _EM_INVALID) ret |= FENV_Y_INVALID;
1297 if (y & _EM_DENORMAL) ret |= FENV_Y_DENORMAL;
1298 if (y & _EM_ZERODIVIDE) ret |= FENV_Y_ZERODIVIDE;
1299 if (y & _EM_OVERFLOW) ret |= FENV_Y_OVERFLOW;
1300 if (y & _EM_UNDERFLOW) ret |= FENV_Y_UNDERFLOW;
1301 if (y & _EM_INEXACT) ret |= FENV_Y_INEXACT;
1302 if (y & _RC_UP) ret |= FENV_Y_UP;
1303 if (y & _RC_DOWN) ret |= FENV_Y_DOWN;
1304 if (y & _DN_FLUSH) ret |= FENV_Y_FLUSH;
1305 if (y & _DN_FLUSH_OPERANDS_SAVE_RESULTS) ret |= FENV_Y_FLUSH_SAVE;
1306 y &= ~(_MCW_EM | _MCW_IC | _MCW_RC | _MCW_DN);
1308 if(x || y) FIXME("unsupported flags: %x, %x\n", x, y);
1309 return ret;
1312 /* decodes x87/sse control/status word, returns FALSE on error */
1313 static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y)
1315 *x = *y = 0;
1316 if ((enc & FENV_X_INVALID) == FENV_X_INVALID) *x |= _EM_INVALID;
1317 if ((enc & FENV_X_DENORMAL) == FENV_X_DENORMAL) *x |= _EM_DENORMAL;
1318 if ((enc & FENV_X_ZERODIVIDE) == FENV_X_ZERODIVIDE) *x |= _EM_ZERODIVIDE;
1319 if ((enc & FENV_X_OVERFLOW) == FENV_X_OVERFLOW) *x |= _EM_OVERFLOW;
1320 if ((enc & FENV_X_UNDERFLOW) == FENV_X_UNDERFLOW) *x |= _EM_UNDERFLOW;
1321 if ((enc & FENV_X_INEXACT) == FENV_X_INEXACT) *x |= _EM_INEXACT;
1322 if ((enc & FENV_X_AFFINE) == FENV_X_AFFINE) *x |= _IC_AFFINE;
1323 if ((enc & FENV_X_UP) == FENV_X_UP) *x |= _RC_UP;
1324 if ((enc & FENV_X_DOWN) == FENV_X_DOWN) *x |= _RC_DOWN;
1325 if ((enc & FENV_X_24) == FENV_X_24) *x |= _PC_24;
1326 if ((enc & FENV_X_53) == FENV_X_53) *x |= _PC_53;
1328 if ((enc & FENV_Y_INVALID) == FENV_Y_INVALID) *y |= _EM_INVALID;
1329 if ((enc & FENV_Y_DENORMAL) == FENV_Y_DENORMAL) *y |= _EM_DENORMAL;
1330 if ((enc & FENV_Y_ZERODIVIDE) == FENV_Y_ZERODIVIDE) *y |= _EM_ZERODIVIDE;
1331 if ((enc & FENV_Y_OVERFLOW) == FENV_Y_OVERFLOW) *y |= _EM_OVERFLOW;
1332 if ((enc & FENV_Y_UNDERFLOW) == FENV_Y_UNDERFLOW) *y |= _EM_UNDERFLOW;
1333 if ((enc & FENV_Y_INEXACT) == FENV_Y_INEXACT) *y |= _EM_INEXACT;
1334 if ((enc & FENV_Y_UP) == FENV_Y_UP) *y |= _RC_UP;
1335 if ((enc & FENV_Y_DOWN) == FENV_Y_DOWN) *y |= _RC_DOWN;
1336 if ((enc & FENV_Y_FLUSH) == FENV_Y_FLUSH) *y |= _DN_FLUSH;
1337 if ((enc & FENV_Y_FLUSH_SAVE) == FENV_Y_FLUSH_SAVE) *y |= _DN_FLUSH_OPERANDS_SAVE_RESULTS;
1339 if (fenv_encode(*x, *y) != enc)
1341 WARN("can't decode: %lx\n", enc);
1342 return FALSE;
1344 return TRUE;
1346 #elif _MSVCR_VER >= 120
1347 static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y)
1349 if (y & _EM_DENORMAL)
1350 y = (y & ~_EM_DENORMAL) | 0x20;
1352 return x | y;
1355 static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y)
1357 if (enc & 0x20)
1358 enc = (enc & ~0x20) | _EM_DENORMAL;
1360 *x = *y = enc;
1361 return TRUE;
1363 #endif
1365 #if _MSVCR_VER>=120
1366 /*********************************************************************
1367 * fegetenv (MSVCR120.@)
1369 int CDECL fegetenv(fenv_t *env)
1371 #if _MSVCR_VER>=140 && defined(__i386__)
1372 unsigned int x87, sse;
1373 __control87_2(0, 0, &x87, &sse);
1374 env->_Fe_ctl = fenv_encode(x87, sse);
1375 _statusfp2(&x87, &sse);
1376 env->_Fe_stat = fenv_encode(x87, sse);
1377 #elif _MSVCR_VER>=140
1378 env->_Fe_ctl = fenv_encode(0, _control87(0, 0));
1379 env->_Fe_stat = fenv_encode(0, _statusfp());
1380 #else
1381 env->_Fe_ctl = _controlfp(0, 0) & (_EM_INEXACT | _EM_UNDERFLOW |
1382 _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID | _MCW_RC);
1383 env->_Fe_stat = _statusfp();
1384 #endif
1385 return 0;
1388 /*********************************************************************
1389 * feupdateenv (MSVCR120.@)
1391 int CDECL feupdateenv(const fenv_t *env)
1393 fenv_t set;
1394 fegetenv(&set);
1395 set._Fe_ctl = env->_Fe_ctl;
1396 set._Fe_stat |= env->_Fe_stat;
1397 return fesetenv(&set);
1400 /*********************************************************************
1401 * fetestexcept (MSVCR120.@)
1403 int CDECL fetestexcept(int flags)
1405 return _statusfp() & flags;
1408 /*********************************************************************
1409 * fesetexceptflag (MSVCR120.@)
1411 int CDECL fesetexceptflag(const fexcept_t *status, int excepts)
1413 fenv_t env;
1415 excepts &= FE_ALL_EXCEPT;
1416 if(!excepts)
1417 return 0;
1419 fegetenv(&env);
1420 env._Fe_stat &= ~fenv_encode(excepts, excepts);
1421 env._Fe_stat |= *status & fenv_encode(excepts, excepts);
1422 return fesetenv(&env);
1425 /*********************************************************************
1426 * feraiseexcept (MSVCR120.@)
1428 int CDECL feraiseexcept(int flags)
1430 fenv_t env;
1432 flags &= FE_ALL_EXCEPT;
1433 fegetenv(&env);
1434 env._Fe_stat |= fenv_encode(flags, flags);
1435 return fesetenv(&env);
1438 /*********************************************************************
1439 * feclearexcept (MSVCR120.@)
1441 int CDECL feclearexcept(int flags)
1443 fenv_t env;
1445 fegetenv(&env);
1446 flags &= FE_ALL_EXCEPT;
1447 env._Fe_stat &= ~fenv_encode(flags, flags);
1448 return fesetenv(&env);
1451 /*********************************************************************
1452 * fegetexceptflag (MSVCR120.@)
1454 int CDECL fegetexceptflag(fexcept_t *status, int excepts)
1456 #if _MSVCR_VER>=140 && defined(__i386__)
1457 unsigned int x87, sse;
1458 _statusfp2(&x87, &sse);
1459 *status = fenv_encode(x87 & excepts, sse & excepts);
1460 #else
1461 *status = fenv_encode(0, _statusfp() & excepts);
1462 #endif
1463 return 0;
1465 #endif
1467 #if _MSVCR_VER>=140
1468 /*********************************************************************
1469 * __fpe_flt_rounds (UCRTBASE.@)
1471 int CDECL __fpe_flt_rounds(void)
1473 unsigned int fpc = _controlfp(0, 0) & _RC_CHOP;
1475 TRACE("()\n");
1477 switch(fpc) {
1478 case _RC_CHOP: return 0;
1479 case _RC_NEAR: return 1;
1480 case _RC_UP: return 2;
1481 default: return 3;
1484 #endif
1486 #if _MSVCR_VER>=120
1488 /*********************************************************************
1489 * fegetround (MSVCR120.@)
1491 int CDECL fegetround(void)
1493 return _controlfp(0, 0) & _MCW_RC;
1496 /*********************************************************************
1497 * fesetround (MSVCR120.@)
1499 int CDECL fesetround(int round_mode)
1501 if (round_mode & (~_MCW_RC))
1502 return 1;
1503 _controlfp(round_mode, _MCW_RC);
1504 return 0;
1507 #endif /* _MSVCR_VER>=120 */
1509 /*********************************************************************
1510 * _finite (MSVCRT.@)
1512 int CDECL _finite(double num)
1514 union { double f; UINT64 i; } u = { num };
1515 return (u.i & ~0ull >> 1) < 0x7ffull << 52;
1518 /*********************************************************************
1519 * _fpreset (MSVCRT.@)
1521 void CDECL _fpreset(void)
1523 #if (defined(__GNUC__) || defined(__clang__)) && defined(__i386__)
1524 const unsigned int x86_cw = 0x27f;
1525 __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
1526 if (sse2_supported)
1528 unsigned int cw = _MCW_EM, sw = 0;
1529 _setfp_sse(&cw, ~0, &sw, ~0);
1531 #else
1532 unsigned int cw = _MCW_EM, sw = 0;
1533 _setfp(&cw, ~0, &sw, ~0);
1534 #endif
1537 #if _MSVCR_VER>=120
1538 /*********************************************************************
1539 * fesetenv (MSVCR120.@)
1541 int CDECL fesetenv(const fenv_t *env)
1543 unsigned int x87_cw, cw, x87_stat, stat;
1544 unsigned int mask;
1546 TRACE( "(%p)\n", env );
1548 if (!env->_Fe_ctl && !env->_Fe_stat) {
1549 _fpreset();
1550 return 0;
1553 if (!fenv_decode(env->_Fe_ctl, &x87_cw, &cw))
1554 return 1;
1555 if (!fenv_decode(env->_Fe_stat, &x87_stat, &stat))
1556 return 1;
1558 #if _MSVCR_VER >= 140
1559 mask = ~0;
1560 #else
1561 mask = _EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW
1562 | _EM_ZERODIVIDE | _EM_INVALID | _MCW_RC;
1563 #endif
1565 #ifdef __i386__
1566 _setfp(&x87_cw, mask, &x87_stat, ~0);
1567 if (sse2_supported)
1568 _setfp_sse(&cw, mask, &stat, ~0);
1569 return 0;
1570 #else
1571 _setfp(&cw, mask, &stat, ~0);
1572 return 0;
1573 #endif
1575 #endif
1577 /*********************************************************************
1578 * _isnan (MSVCRT.@)
1580 int CDECL _isnan(double num)
1582 union { double f; UINT64 i; } u = { num };
1583 return (u.i & ~0ull >> 1) > 0x7ffull << 52;
1586 #if _MSVCR_VER>=120
1588 /*********************************************************************
1589 * rint (MSVCR120.@)
1591 double CDECL MSVCRT_rint(double x)
1593 unsigned cw;
1594 double y;
1596 cw = _controlfp(0, 0);
1597 if ((cw & _MCW_PC) != _PC_53)
1598 _controlfp(_PC_53, _MCW_PC);
1599 y = rint(x);
1600 if ((cw & _MCW_PC) != _PC_53)
1601 _controlfp(cw, _MCW_PC);
1602 return y;
1605 /*********************************************************************
1606 * _nearbyint (MSVCR120.@)
1608 * Based on musl: src/math/nearbyteint.c
1610 double CDECL nearbyint(double x)
1612 BOOL update_cw, update_sw;
1613 unsigned int cw, sw;
1615 _setfp(&cw, 0, &sw, 0);
1616 update_cw = !(cw & _EM_INEXACT);
1617 update_sw = !(sw & _SW_INEXACT);
1618 if (update_cw)
1620 cw |= _EM_INEXACT;
1621 _setfp(&cw, _EM_INEXACT, NULL, 0);
1623 x = MSVCRT_rint(x);
1624 if (update_cw || update_sw)
1626 sw = 0;
1627 cw &= ~_EM_INEXACT;
1628 _setfp(update_cw ? &cw : NULL, _EM_INEXACT,
1629 update_sw ? &sw : NULL, _SW_INEXACT);
1631 return x;
1634 /*********************************************************************
1635 * _nearbyintf (MSVCR120.@)
1637 * Based on musl: src/math/nearbyteintf.c
1639 float CDECL nearbyintf(float x)
1641 BOOL update_cw, update_sw;
1642 unsigned int cw, sw;
1644 _setfp(&cw, 0, &sw, 0);
1645 update_cw = !(cw & _EM_INEXACT);
1646 update_sw = !(sw & _SW_INEXACT);
1647 if (update_cw)
1649 cw |= _EM_INEXACT;
1650 _setfp(&cw, _EM_INEXACT, NULL, 0);
1652 x = rintf(x);
1653 if (update_cw || update_sw)
1655 sw = 0;
1656 cw &= ~_EM_INEXACT;
1657 _setfp(update_cw ? &cw : NULL, _EM_INEXACT,
1658 update_sw ? &sw : NULL, _SW_INEXACT);
1660 return x;
1663 #endif /* _MSVCR_VER>=120 */
1665 /*********************************************************************
1666 * _ecvt (MSVCRT.@)
1668 char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
1670 int prec, len;
1671 thread_data_t *data = msvcrt_get_thread_data();
1672 /* FIXME: check better for overflow (native supports over 300 chars) */
1673 ndigits = min( ndigits, 80 - 8); /* 8 : space for sign, dec point, "e",
1674 * 4 for exponent and one for
1675 * terminating '\0' */
1676 if (!data->efcvt_buffer)
1677 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
1679 /* handle cases with zero ndigits or less */
1680 prec = ndigits;
1681 if( prec < 1) prec = 2;
1682 len = _snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
1684 if (data->efcvt_buffer[0] == '-') {
1685 memmove( data->efcvt_buffer, data->efcvt_buffer + 1, len-- );
1686 *sign = 1;
1687 } else *sign = 0;
1689 /* take the decimal "point away */
1690 if( prec != 1)
1691 memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
1692 /* take the exponential "e" out */
1693 data->efcvt_buffer[ prec] = '\0';
1694 /* read the exponent */
1695 sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
1696 (*decpt)++;
1697 /* adjust for some border cases */
1698 if( data->efcvt_buffer[0] == '0')/* value is zero */
1699 *decpt = 0;
1700 /* handle cases with zero ndigits or less */
1701 if( ndigits < 1){
1702 if( data->efcvt_buffer[ 0] >= '5')
1703 (*decpt)++;
1704 data->efcvt_buffer[ 0] = '\0';
1706 TRACE("out=\"%s\"\n",data->efcvt_buffer);
1707 return data->efcvt_buffer;
1710 /*********************************************************************
1711 * _ecvt_s (MSVCRT.@)
1713 int CDECL _ecvt_s( char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign )
1715 int prec, len;
1716 char *result;
1718 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
1719 if (!MSVCRT_CHECK_PMT(decpt != NULL)) return EINVAL;
1720 if (!MSVCRT_CHECK_PMT(sign != NULL)) return EINVAL;
1721 if (!MSVCRT_CHECK_PMT_ERR( length > 2, ERANGE )) return ERANGE;
1722 if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, ERANGE )) return ERANGE;
1724 /* handle cases with zero ndigits or less */
1725 prec = ndigits;
1726 if( prec < 1) prec = 2;
1727 result = malloc(prec + 8);
1729 len = _snprintf(result, prec + 8, "%.*le", prec - 1, number);
1730 if (result[0] == '-') {
1731 memmove( result, result + 1, len-- );
1732 *sign = 1;
1733 } else *sign = 0;
1735 /* take the decimal "point away */
1736 if( prec != 1)
1737 memmove( result + 1, result + 2, len - 1 );
1738 /* take the exponential "e" out */
1739 result[ prec] = '\0';
1740 /* read the exponent */
1741 sscanf( result + prec + 1, "%d", decpt);
1742 (*decpt)++;
1743 /* adjust for some border cases */
1744 if( result[0] == '0')/* value is zero */
1745 *decpt = 0;
1746 /* handle cases with zero ndigits or less */
1747 if( ndigits < 1){
1748 if( result[ 0] >= '5')
1749 (*decpt)++;
1750 result[ 0] = '\0';
1752 memcpy( buffer, result, max(ndigits + 1, 1) );
1753 free( result );
1754 return 0;
1757 /***********************************************************************
1758 * _fcvt (MSVCRT.@)
1760 char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
1762 thread_data_t *data = msvcrt_get_thread_data();
1763 int stop, dec1, dec2;
1764 char *ptr1, *ptr2, *first;
1765 char buf[80]; /* ought to be enough */
1766 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
1768 if (!data->efcvt_buffer)
1769 data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
1771 stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1772 ptr1 = buf;
1773 ptr2 = data->efcvt_buffer;
1774 first = NULL;
1775 dec1 = 0;
1776 dec2 = 0;
1778 if (*ptr1 == '-') {
1779 *sign = 1;
1780 ptr1++;
1781 } else *sign = 0;
1783 /* For numbers below the requested resolution, work out where
1784 the decimal point will be rather than finding it in the string */
1785 if (number < 1.0 && number > 0.0) {
1786 dec2 = log10(number + 1e-10);
1787 if (-dec2 <= ndigits) dec2 = 0;
1790 /* If requested digits is zero or less, we will need to truncate
1791 * the returned string */
1792 if (ndigits < 1) {
1793 stop += ndigits;
1796 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1797 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
1798 if (!first) first = ptr2;
1799 if ((ptr1 - buf) < stop) {
1800 *ptr2++ = *ptr1++;
1801 } else {
1802 ptr1++;
1804 dec1++;
1807 if (ndigits > 0) {
1808 ptr1++;
1809 if (!first) {
1810 while (*ptr1 == '0') { /* Process leading zeroes */
1811 *ptr2++ = *ptr1++;
1812 dec1--;
1815 while (*ptr1 != '\0') {
1816 if (!first) first = ptr2;
1817 *ptr2++ = *ptr1++;
1821 *ptr2 = '\0';
1823 /* We never found a non-zero digit, then our number is either
1824 * smaller than the requested precision, or 0.0 */
1825 if (!first) {
1826 if (number > 0.0) {
1827 first = ptr2;
1828 } else {
1829 first = data->efcvt_buffer;
1830 dec1 = 0;
1834 *decpt = dec2 ? dec2 : dec1;
1835 return first;
1838 /***********************************************************************
1839 * _fcvt_s (MSVCRT.@)
1841 int CDECL _fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int *decpt, int *sign)
1843 int stop, dec1, dec2;
1844 char *ptr1, *ptr2, *first;
1845 char buf[80]; /* ought to be enough */
1846 char decimal_separator = get_locinfo()->lconv->decimal_point[0];
1848 if (!outbuffer || !decpt || !sign || size == 0)
1850 *_errno() = EINVAL;
1851 return EINVAL;
1854 stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1855 ptr1 = buf;
1856 ptr2 = outbuffer;
1857 first = NULL;
1858 dec1 = 0;
1859 dec2 = 0;
1861 if (*ptr1 == '-') {
1862 *sign = 1;
1863 ptr1++;
1864 } else *sign = 0;
1866 /* For numbers below the requested resolution, work out where
1867 the decimal point will be rather than finding it in the string */
1868 if (number < 1.0 && number > 0.0) {
1869 dec2 = log10(number + 1e-10);
1870 if (-dec2 <= ndigits) dec2 = 0;
1873 /* If requested digits is zero or less, we will need to truncate
1874 * the returned string */
1875 if (ndigits < 1) {
1876 stop += ndigits;
1879 while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1880 while (*ptr1 != '\0' && *ptr1 != decimal_separator) {
1881 if (!first) first = ptr2;
1882 if ((ptr1 - buf) < stop) {
1883 if (size > 1) {
1884 *ptr2++ = *ptr1++;
1885 size--;
1887 } else {
1888 ptr1++;
1890 dec1++;
1893 if (ndigits > 0) {
1894 ptr1++;
1895 if (!first) {
1896 while (*ptr1 == '0') { /* Process leading zeroes */
1897 if (number == 0.0 && size > 1) {
1898 *ptr2++ = '0';
1899 size--;
1901 ptr1++;
1902 dec1--;
1905 while (*ptr1 != '\0') {
1906 if (!first) first = ptr2;
1907 if (size > 1) {
1908 *ptr2++ = *ptr1++;
1909 size--;
1914 *ptr2 = '\0';
1916 /* We never found a non-zero digit, then our number is either
1917 * smaller than the requested precision, or 0.0 */
1918 if (!first && (number <= 0.0))
1919 dec1 = 0;
1921 *decpt = dec2 ? dec2 : dec1;
1922 return 0;
1925 /***********************************************************************
1926 * _gcvt (MSVCRT.@)
1928 char * CDECL _gcvt( double number, int ndigit, char *buff )
1930 if(!buff) {
1931 *_errno() = EINVAL;
1932 return NULL;
1935 if(ndigit < 0) {
1936 *_errno() = ERANGE;
1937 return NULL;
1940 sprintf(buff, "%.*g", ndigit, number);
1941 return buff;
1944 /***********************************************************************
1945 * _gcvt_s (MSVCRT.@)
1947 int CDECL _gcvt_s(char *buff, size_t size, double number, int digits)
1949 int len;
1951 if(!buff) {
1952 *_errno() = EINVAL;
1953 return EINVAL;
1956 if( digits<0 || digits>=size) {
1957 if(size)
1958 buff[0] = '\0';
1960 *_errno() = ERANGE;
1961 return ERANGE;
1964 len = _scprintf("%.*g", digits, number);
1965 if(len > size) {
1966 buff[0] = '\0';
1967 *_errno() = ERANGE;
1968 return ERANGE;
1971 sprintf(buff, "%.*g", digits, number);
1972 return 0;
1975 #include <stdlib.h> /* div_t, ldiv_t */
1977 /*********************************************************************
1978 * div (MSVCRT.@)
1979 * VERSION
1980 * [i386] Windows binary compatible - returns the struct in eax/edx.
1982 #ifdef __i386__
1983 unsigned __int64 CDECL div(int num, int denom)
1985 union {
1986 div_t div;
1987 unsigned __int64 uint64;
1988 } ret;
1990 ret.div.quot = num / denom;
1991 ret.div.rem = num % denom;
1992 return ret.uint64;
1994 #else
1995 /*********************************************************************
1996 * div (MSVCRT.@)
1997 * VERSION
1998 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2000 div_t CDECL div(int num, int denom)
2002 div_t ret;
2004 ret.quot = num / denom;
2005 ret.rem = num % denom;
2006 return ret;
2008 #endif /* ifdef __i386__ */
2011 /*********************************************************************
2012 * ldiv (MSVCRT.@)
2013 * VERSION
2014 * [i386] Windows binary compatible - returns the struct in eax/edx.
2016 #ifdef __i386__
2017 unsigned __int64 CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
2019 union {
2020 ldiv_t ldiv;
2021 unsigned __int64 uint64;
2022 } ret;
2024 ret.ldiv.quot = num / denom;
2025 ret.ldiv.rem = num % denom;
2026 return ret.uint64;
2028 #else
2029 /*********************************************************************
2030 * ldiv (MSVCRT.@)
2031 * VERSION
2032 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
2034 ldiv_t CDECL ldiv(__msvcrt_long num, __msvcrt_long denom)
2036 ldiv_t ret;
2038 ret.quot = num / denom;
2039 ret.rem = num % denom;
2040 return ret;
2042 #endif /* ifdef __i386__ */
2044 #if _MSVCR_VER>=100
2045 /*********************************************************************
2046 * lldiv (MSVCR100.@)
2048 lldiv_t CDECL lldiv(__int64 num, __int64 denom)
2050 lldiv_t ret;
2052 ret.quot = num / denom;
2053 ret.rem = num % denom;
2055 return ret;
2057 #endif
2059 #ifdef __i386__
2061 /*********************************************************************
2062 * _adjust_fdiv (MSVCRT.@)
2063 * Used by the MSVC compiler to work around the Pentium FDIV bug.
2065 int MSVCRT__adjust_fdiv = 0;
2067 /***********************************************************************
2068 * _adj_fdiv_m16i (MSVCRT.@)
2070 * NOTE
2071 * I _think_ this function is intended to work around the Pentium
2072 * fdiv bug.
2074 void __stdcall _adj_fdiv_m16i( short arg )
2076 TRACE("(): stub\n");
2079 /***********************************************************************
2080 * _adj_fdiv_m32 (MSVCRT.@)
2082 * NOTE
2083 * I _think_ this function is intended to work around the Pentium
2084 * fdiv bug.
2086 void __stdcall _adj_fdiv_m32( unsigned int arg )
2088 TRACE("(): stub\n");
2091 /***********************************************************************
2092 * _adj_fdiv_m32i (MSVCRT.@)
2094 * NOTE
2095 * I _think_ this function is intended to work around the Pentium
2096 * fdiv bug.
2098 void __stdcall _adj_fdiv_m32i( int arg )
2100 TRACE("(): stub\n");
2103 /***********************************************************************
2104 * _adj_fdiv_m64 (MSVCRT.@)
2106 * NOTE
2107 * I _think_ this function is intended to work around the Pentium
2108 * fdiv bug.
2110 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
2112 TRACE("(): stub\n");
2115 /***********************************************************************
2116 * _adj_fdiv_r (MSVCRT.@)
2117 * FIXME
2118 * This function is likely to have the wrong number of arguments.
2120 * NOTE
2121 * I _think_ this function is intended to work around the Pentium
2122 * fdiv bug.
2124 void _adj_fdiv_r(void)
2126 TRACE("(): stub\n");
2129 /***********************************************************************
2130 * _adj_fdivr_m16i (MSVCRT.@)
2132 * NOTE
2133 * I _think_ this function is intended to work around the Pentium
2134 * fdiv bug.
2136 void __stdcall _adj_fdivr_m16i( short arg )
2138 TRACE("(): stub\n");
2141 /***********************************************************************
2142 * _adj_fdivr_m32 (MSVCRT.@)
2144 * NOTE
2145 * I _think_ this function is intended to work around the Pentium
2146 * fdiv bug.
2148 void __stdcall _adj_fdivr_m32( unsigned int arg )
2150 TRACE("(): stub\n");
2153 /***********************************************************************
2154 * _adj_fdivr_m32i (MSVCRT.@)
2156 * NOTE
2157 * I _think_ this function is intended to work around the Pentium
2158 * fdiv bug.
2160 void __stdcall _adj_fdivr_m32i( int arg )
2162 TRACE("(): stub\n");
2165 /***********************************************************************
2166 * _adj_fdivr_m64 (MSVCRT.@)
2168 * NOTE
2169 * I _think_ this function is intended to work around the Pentium
2170 * fdiv bug.
2172 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
2174 TRACE("(): stub\n");
2177 /***********************************************************************
2178 * _adj_fpatan (MSVCRT.@)
2179 * FIXME
2180 * This function is likely to have the wrong number of arguments.
2182 * NOTE
2183 * I _think_ this function is intended to work around the Pentium
2184 * fdiv bug.
2186 void _adj_fpatan(void)
2188 TRACE("(): stub\n");
2191 /***********************************************************************
2192 * _adj_fprem (MSVCRT.@)
2193 * FIXME
2194 * This function is likely to have the wrong number of arguments.
2196 * NOTE
2197 * I _think_ this function is intended to work around the Pentium
2198 * fdiv bug.
2200 void _adj_fprem(void)
2202 TRACE("(): stub\n");
2205 /***********************************************************************
2206 * _adj_fprem1 (MSVCRT.@)
2207 * FIXME
2208 * This function is likely to have the wrong number of arguments.
2210 * NOTE
2211 * I _think_ this function is intended to work around the Pentium
2212 * fdiv bug.
2214 void _adj_fprem1(void)
2216 TRACE("(): stub\n");
2219 /***********************************************************************
2220 * _adj_fptan (MSVCRT.@)
2221 * FIXME
2222 * This function is likely to have the wrong number of arguments.
2224 * NOTE
2225 * I _think_ this function is intended to work around the Pentium
2226 * fdiv bug.
2228 void _adj_fptan(void)
2230 TRACE("(): stub\n");
2233 /***********************************************************************
2234 * _safe_fdiv (MSVCRT.@)
2235 * FIXME
2236 * This function is likely to have the wrong number of arguments.
2238 * NOTE
2239 * I _think_ this function is intended to work around the Pentium
2240 * fdiv bug.
2242 void _safe_fdiv(void)
2244 TRACE("(): stub\n");
2247 /***********************************************************************
2248 * _safe_fdivr (MSVCRT.@)
2249 * FIXME
2250 * This function is likely to have the wrong number of arguments.
2252 * NOTE
2253 * I _think_ this function is intended to work around the Pentium
2254 * fdiv bug.
2256 void _safe_fdivr(void)
2258 TRACE("(): stub\n");
2261 /***********************************************************************
2262 * _safe_fprem (MSVCRT.@)
2263 * FIXME
2264 * This function is likely to have the wrong number of arguments.
2266 * NOTE
2267 * I _think_ this function is intended to work around the Pentium
2268 * fdiv bug.
2270 void _safe_fprem(void)
2272 TRACE("(): stub\n");
2275 /***********************************************************************
2276 * _safe_fprem1 (MSVCRT.@)
2278 * FIXME
2279 * This function is likely to have the wrong number of arguments.
2281 * NOTE
2282 * I _think_ this function is intended to work around the Pentium
2283 * fdiv bug.
2285 void _safe_fprem1(void)
2287 TRACE("(): stub\n");
2290 /***********************************************************************
2291 * __libm_sse2_acos (MSVCRT.@)
2293 void __cdecl __libm_sse2_acos(void)
2295 double d;
2296 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2297 d = acos( d );
2298 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2301 /***********************************************************************
2302 * __libm_sse2_acosf (MSVCRT.@)
2304 void __cdecl __libm_sse2_acosf(void)
2306 float f;
2307 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2308 f = acosf( f );
2309 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2312 /***********************************************************************
2313 * __libm_sse2_asin (MSVCRT.@)
2315 void __cdecl __libm_sse2_asin(void)
2317 double d;
2318 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2319 d = asin( d );
2320 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2323 /***********************************************************************
2324 * __libm_sse2_asinf (MSVCRT.@)
2326 void __cdecl __libm_sse2_asinf(void)
2328 float f;
2329 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2330 f = asinf( f );
2331 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2334 /***********************************************************************
2335 * __libm_sse2_atan (MSVCRT.@)
2337 void __cdecl __libm_sse2_atan(void)
2339 double d;
2340 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2341 d = atan( d );
2342 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2345 /***********************************************************************
2346 * __libm_sse2_atan2 (MSVCRT.@)
2348 void __cdecl __libm_sse2_atan2(void)
2350 double d1, d2;
2351 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2352 d1 = atan2( d1, d2 );
2353 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2356 /***********************************************************************
2357 * __libm_sse2_atanf (MSVCRT.@)
2359 void __cdecl __libm_sse2_atanf(void)
2361 float f;
2362 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2363 f = atanf( f );
2364 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2367 /***********************************************************************
2368 * __libm_sse2_cos (MSVCRT.@)
2370 void __cdecl __libm_sse2_cos(void)
2372 double d;
2373 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2374 d = cos( d );
2375 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2378 /***********************************************************************
2379 * __libm_sse2_cosf (MSVCRT.@)
2381 void __cdecl __libm_sse2_cosf(void)
2383 float f;
2384 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2385 f = cosf( f );
2386 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2389 /***********************************************************************
2390 * __libm_sse2_exp (MSVCRT.@)
2392 void __cdecl __libm_sse2_exp(void)
2394 double d;
2395 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2396 d = exp( d );
2397 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2400 /***********************************************************************
2401 * __libm_sse2_expf (MSVCRT.@)
2403 void __cdecl __libm_sse2_expf(void)
2405 float f;
2406 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2407 f = expf( f );
2408 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2411 /***********************************************************************
2412 * __libm_sse2_log (MSVCRT.@)
2414 void __cdecl __libm_sse2_log(void)
2416 double d;
2417 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2418 d = log( d );
2419 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2422 /***********************************************************************
2423 * __libm_sse2_log10 (MSVCRT.@)
2425 void __cdecl __libm_sse2_log10(void)
2427 double d;
2428 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2429 d = log10( d );
2430 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2433 /***********************************************************************
2434 * __libm_sse2_log10f (MSVCRT.@)
2436 void __cdecl __libm_sse2_log10f(void)
2438 float f;
2439 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2440 f = log10f( f );
2441 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2444 /***********************************************************************
2445 * __libm_sse2_logf (MSVCRT.@)
2447 void __cdecl __libm_sse2_logf(void)
2449 float f;
2450 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2451 f = logf( f );
2452 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2455 /***********************************************************************
2456 * __libm_sse2_pow (MSVCRT.@)
2458 void __cdecl __libm_sse2_pow(void)
2460 double d1, d2;
2461 __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2462 d1 = pow( d1, d2 );
2463 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2466 /***********************************************************************
2467 * __libm_sse2_powf (MSVCRT.@)
2469 void __cdecl __libm_sse2_powf(void)
2471 float f1, f2;
2472 __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
2473 f1 = powf( f1, f2 );
2474 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
2477 /***********************************************************************
2478 * __libm_sse2_sin (MSVCRT.@)
2480 void __cdecl __libm_sse2_sin(void)
2482 double d;
2483 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2484 d = sin( d );
2485 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2488 /***********************************************************************
2489 * __libm_sse2_sinf (MSVCRT.@)
2491 void __cdecl __libm_sse2_sinf(void)
2493 float f;
2494 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2495 f = sinf( f );
2496 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2499 /***********************************************************************
2500 * __libm_sse2_tan (MSVCRT.@)
2502 void __cdecl __libm_sse2_tan(void)
2504 double d;
2505 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2506 d = tan( d );
2507 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2510 /***********************************************************************
2511 * __libm_sse2_tanf (MSVCRT.@)
2513 void __cdecl __libm_sse2_tanf(void)
2515 float f;
2516 __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2517 f = tanf( f );
2518 __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2521 /***********************************************************************
2522 * __libm_sse2_sqrt_precise (MSVCR110.@)
2524 void __cdecl __libm_sse2_sqrt_precise(void)
2526 unsigned int cw;
2527 double d;
2529 __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2530 __control87_2(0, 0, NULL, &cw);
2531 if (cw & _MCW_RC)
2533 d = sqrt(d);
2534 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2535 return;
2538 if (!sqrt_validate(&d, FALSE))
2540 __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2541 return;
2543 __asm__ __volatile__( "call " __ASM_NAME( "sse2_sqrt" ) );
2545 #endif /* __i386__ */
2547 #if _MSVCR_VER>=120
2549 /*********************************************************************
2550 * lrint (MSVCR120.@)
2552 __msvcrt_long CDECL lrint(double x)
2554 double d;
2556 d = MSVCRT_rint(x);
2557 if ((d < 0 && d != (double)(__msvcrt_long)d)
2558 || (d >= 0 && d != (double)(__msvcrt_ulong)d)) {
2559 *_errno() = EDOM;
2560 return 0;
2562 return d;
2565 /*********************************************************************
2566 * lrintf (MSVCR120.@)
2568 __msvcrt_long CDECL lrintf(float x)
2570 float f;
2572 f = rintf(x);
2573 if ((f < 0 && f != (float)(__msvcrt_long)f)
2574 || (f >= 0 && f != (float)(__msvcrt_ulong)f)) {
2575 *_errno() = EDOM;
2576 return 0;
2578 return f;
2581 /*********************************************************************
2582 * llrint (MSVCR120.@)
2584 __int64 CDECL llrint(double x)
2586 double d;
2588 d = MSVCRT_rint(x);
2589 if ((d < 0 && d != (double)(__int64)d)
2590 || (d >= 0 && d != (double)(unsigned __int64)d)) {
2591 *_errno() = EDOM;
2592 return 0;
2594 return d;
2597 /*********************************************************************
2598 * llrintf (MSVCR120.@)
2600 __int64 CDECL llrintf(float x)
2602 float f;
2604 f = rintf(x);
2605 if ((f < 0 && f != (float)(__int64)f)
2606 || (f >= 0 && f != (float)(unsigned __int64)f)) {
2607 *_errno() = EDOM;
2608 return 0;
2610 return f;
2613 /*********************************************************************
2614 * lround (MSVCR120.@)
2616 * Copied from musl: src/math/lround.c
2618 __msvcrt_long CDECL lround(double x)
2620 double d = round(x);
2621 if (d != (double)(__msvcrt_long)d) {
2622 *_errno() = EDOM;
2623 return 0;
2625 return d;
2628 /*********************************************************************
2629 * lroundf (MSVCR120.@)
2631 * Copied from musl: src/math/lroundf.c
2633 __msvcrt_long CDECL lroundf(float x)
2635 float f = roundf(x);
2636 if (f != (float)(__msvcrt_long)f) {
2637 *_errno() = EDOM;
2638 return 0;
2640 return f;
2643 /*********************************************************************
2644 * llround (MSVCR120.@)
2646 * Copied from musl: src/math/llround.c
2648 __int64 CDECL llround(double x)
2650 double d = round(x);
2651 if (d != (double)(__int64)d) {
2652 *_errno() = EDOM;
2653 return 0;
2655 return d;
2658 /*********************************************************************
2659 * llroundf (MSVCR120.@)
2661 * Copied from musl: src/math/llroundf.c
2663 __int64 CDECL llroundf(float x)
2665 float f = roundf(x);
2666 if (f != (float)(__int64)f) {
2667 *_errno() = EDOM;
2668 return 0;
2670 return f;
2673 /*********************************************************************
2674 * _dtest (MSVCR120.@)
2676 short CDECL _dtest(double *x)
2678 return _dclass(*x);
2681 /*********************************************************************
2682 * _fdtest (MSVCR120.@)
2684 short CDECL _fdtest(float *x)
2686 return _fdclass(*x);
2689 /*********************************************************************
2690 * _fdsign (MSVCR120.@)
2692 int CDECL _fdsign(float x)
2694 union { float f; UINT32 i; } u = { x };
2695 return (u.i >> 16) & 0x8000;
2698 /*********************************************************************
2699 * _dsign (MSVCR120.@)
2701 int CDECL _dsign(double x)
2703 union { double f; UINT64 i; } u = { x };
2704 return (u.i >> 48) & 0x8000;
2707 /*********************************************************************
2708 * _dpcomp (MSVCR120.@)
2710 int CDECL _dpcomp(double x, double y)
2712 if(isnan(x) || isnan(y))
2713 return 0;
2715 if(x == y) return 2;
2716 return x < y ? 1 : 4;
2719 /*********************************************************************
2720 * _fdpcomp (MSVCR120.@)
2722 int CDECL _fdpcomp(float x, float y)
2724 return _dpcomp(x, y);
2727 /*********************************************************************
2728 * acosh (MSVCR120.@)
2730 double CDECL MSVCRT_acosh(double x)
2732 if (x < 1)
2734 *_errno() = EDOM;
2735 feraiseexcept(FE_INVALID);
2736 return NAN;
2738 return acosh( x );
2741 /*********************************************************************
2742 * acoshf (MSVCR120.@)
2744 float CDECL MSVCRT_acoshf(float x)
2746 if (x < 1)
2748 *_errno() = EDOM;
2749 feraiseexcept(FE_INVALID);
2750 return NAN;
2752 return acoshf( x );
2755 /*********************************************************************
2756 * atanh (MSVCR120.@)
2758 double CDECL MSVCRT_atanh(double x)
2760 if (fabs(x) > 1)
2762 *_errno() = EDOM;
2763 feraiseexcept(FE_INVALID);
2764 return NAN;
2766 return atanh( x );
2769 /*********************************************************************
2770 * atanhf (MSVCR120.@)
2772 float CDECL MSVCRT_atanhf(float x)
2774 if (fabs(x) > 1)
2776 *_errno() = EDOM;
2777 feraiseexcept(FE_INVALID);
2778 return NAN;
2780 return atanhf( x );
2783 #endif /* _MSVCR_VER>=120 */
2785 /*********************************************************************
2786 * _scalb (MSVCRT.@)
2787 * scalbn (MSVCR120.@)
2788 * scalbln (MSVCR120.@)
2790 double CDECL _scalb(double num, __msvcrt_long power)
2792 return ldexp(num, power);
2795 /*********************************************************************
2796 * _scalbf (MSVCRT.@)
2797 * scalbnf (MSVCR120.@)
2798 * scalblnf (MSVCR120.@)
2800 float CDECL _scalbf(float num, __msvcrt_long power)
2802 return ldexp(num, power);
2805 #if _MSVCR_VER == 120 /* other versions call remainder() directly */
2807 /*********************************************************************
2808 * remainder (MSVCR120.@)
2810 double CDECL MSVCRT_remainder(double x, double y)
2812 #ifdef __x86_64__
2813 if (isnan(x) || isnan(y)) *_errno() = EDOM;
2814 #endif
2815 return remainder(x, y);
2818 /*********************************************************************
2819 * remainderf (MSVCR120.@)
2821 float CDECL MSVCRT_remainderf(float x, float y)
2823 #ifdef __x86_64__
2824 if (isnan(x) || isnan(y)) *_errno() = EDOM;
2825 #endif
2826 return remainderf(x, y);
2829 #endif /* _MSVCR_VER == 120 */
2831 #if _MSVCR_VER>=120
2833 /*********************************************************************
2834 * _except1 (MSVCR120.@)
2835 * TODO:
2836 * - find meaning of ignored cw and operation bits
2837 * - unk parameter
2839 double CDECL _except1(DWORD fpe, _FP_OPERATION_CODE op, double arg, double res, DWORD cw, void *unk)
2841 ULONG_PTR exception_arg;
2842 DWORD exception = 0;
2843 unsigned int fpword = 0;
2844 WORD operation;
2845 int raise = 0;
2847 TRACE("(%lx %x %lf %lf %lx %p)\n", fpe, op, arg, res, cw, unk);
2849 #ifdef _WIN64
2850 cw = ((cw >> 7) & 0x3f) | ((cw >> 3) & 0xc00);
2851 #endif
2852 operation = op << 5;
2853 exception_arg = (ULONG_PTR)&operation;
2855 if (fpe & 0x1) { /* overflow */
2856 if ((fpe == 0x1 && (cw & 0x8)) || (fpe==0x11 && (cw & 0x28))) {
2857 /* 32-bit version also sets SW_INEXACT here */
2858 raise |= FE_OVERFLOW;
2859 if (fpe & 0x10) raise |= FE_INEXACT;
2860 res = signbit(res) ? -INFINITY : INFINITY;
2861 } else {
2862 exception = EXCEPTION_FLT_OVERFLOW;
2864 } else if (fpe & 0x2) { /* underflow */
2865 if ((fpe == 0x2 && (cw & 0x10)) || (fpe==0x12 && (cw & 0x30))) {
2866 raise |= FE_UNDERFLOW;
2867 if (fpe & 0x10) raise |= FE_INEXACT;
2868 res = signbit(res) ? -0.0 : 0.0;
2869 } else {
2870 exception = EXCEPTION_FLT_UNDERFLOW;
2872 } else if (fpe & 0x4) { /* zerodivide */
2873 if ((fpe == 0x4 && (cw & 0x4)) || (fpe==0x14 && (cw & 0x24))) {
2874 raise |= FE_DIVBYZERO;
2875 if (fpe & 0x10) raise |= FE_INEXACT;
2876 } else {
2877 exception = EXCEPTION_FLT_DIVIDE_BY_ZERO;
2879 } else if (fpe & 0x8) { /* invalid */
2880 if (fpe == 0x8 && (cw & 0x1)) {
2881 raise |= FE_INVALID;
2882 } else {
2883 exception = EXCEPTION_FLT_INVALID_OPERATION;
2885 } else if (fpe & 0x10) { /* inexact */
2886 if (fpe == 0x10 && (cw & 0x20)) {
2887 raise |= FE_INEXACT;
2888 } else {
2889 exception = EXCEPTION_FLT_INEXACT_RESULT;
2893 if (exception)
2894 raise = 0;
2895 feraiseexcept(raise);
2896 if (exception)
2897 RaiseException(exception, 0, 1, &exception_arg);
2899 if (cw & 0x1) fpword |= _EM_INVALID;
2900 if (cw & 0x2) fpword |= _EM_DENORMAL;
2901 if (cw & 0x4) fpword |= _EM_ZERODIVIDE;
2902 if (cw & 0x8) fpword |= _EM_OVERFLOW;
2903 if (cw & 0x10) fpword |= _EM_UNDERFLOW;
2904 if (cw & 0x20) fpword |= _EM_INEXACT;
2905 switch (cw & 0xc00)
2907 case 0xc00: fpword |= _RC_UP|_RC_DOWN; break;
2908 case 0x800: fpword |= _RC_UP; break;
2909 case 0x400: fpword |= _RC_DOWN; break;
2911 switch (cw & 0x300)
2913 case 0x0: fpword |= _PC_24; break;
2914 case 0x200: fpword |= _PC_53; break;
2915 case 0x300: fpword |= _PC_64; break;
2917 if (cw & 0x1000) fpword |= _IC_AFFINE;
2918 _setfp(&fpword, _MCW_EM | _MCW_RC | _MCW_PC | _MCW_IC, NULL, 0);
2920 return res;
2923 _Dcomplex* CDECL _Cbuild(_Dcomplex *ret, double r, double i)
2925 ret->_Val[0] = r;
2926 ret->_Val[1] = i;
2927 return ret;
2930 double CDECL MSVCR120_creal(_Dcomplex z)
2932 return z._Val[0];
2935 #endif /* _MSVCR_VER>=120 */