msvcrt: Added _get_current_locale implementation.
[wine] / dlls / msvcrt / math.c
1 /*
2  * msvcrt.dll math functions
3  *
4  * Copyright 2000 Jon Griffiths
5  *
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.
10  *
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.
15  *
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
19  */
20 #include "config.h"
21
22 #include <stdio.h>
23 #define __USE_ISOC9X 1
24 #define __USE_ISOC99 1
25 #include <math.h>
26 #ifdef HAVE_IEEEFP_H
27 #include <ieeefp.h>
28 #endif
29
30 #include "msvcrt.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
35
36 #ifndef HAVE_FINITE
37 #ifndef finite /* Could be a macro */
38 #ifdef isfinite
39 #define finite(x) isfinite(x)
40 #else
41 #define finite(x) (!isnan(x)) /* At least catch some cases */
42 #endif
43 #endif
44 #endif
45
46 #ifndef signbit
47 #define signbit(x) 0
48 #endif
49
50 typedef int (CDECL *MSVCRT_matherr_func)(struct MSVCRT__exception *);
51
52 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
53
54 static BOOL sse2_supported;
55 static BOOL sse2_enabled;
56
57 void msvcrt_init_math(void)
58 {
59     sse2_supported = sse2_enabled = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
60 }
61
62 /*********************************************************************
63  *      _set_SSE2_enable (MSVCRT.@)
64  */
65 int CDECL MSVCRT__set_SSE2_enable(int flag)
66 {
67     sse2_enabled = flag && sse2_supported;
68     return sse2_enabled;
69 }
70
71 #ifdef __x86_64__
72
73 /*********************************************************************
74  *      MSVCRT_acosf (MSVCRT.@)
75  */
76 float CDECL MSVCRT_acosf( float x )
77 {
78   if (x < -1.0 || x > 1.0 || !finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
79   /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
80    * asin() uses a similar construction. This is bad because as x gets nearer to
81    * 1 the error in the expression "1 - x^2" can get relatively large due to
82    * cancellation. The sqrt() makes things worse. A safer way to calculate
83    * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
84   return atan2f(sqrtf((1 - x) * (1 + x)), x);
85 }
86
87 /*********************************************************************
88  *      MSVCRT_asinf (MSVCRT.@)
89  */
90 float CDECL MSVCRT_asinf( float x )
91 {
92   if (x < -1.0 || x > 1.0 || !finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
93   return atan2f(x, sqrtf((1 - x) * (1 + x)));
94 }
95
96 /*********************************************************************
97  *      MSVCRT_atanf (MSVCRT.@)
98  */
99 float CDECL MSVCRT_atanf( float x )
100 {
101   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
102   return atanf(x);
103 }
104
105 /*********************************************************************
106  *              MSVCRT_atan2f (MSVCRT.@)
107  */
108 float CDECL MSVCRT_atan2f( float x, float y )
109 {
110   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
111   return atan2f(x,y);
112 }
113
114 /*********************************************************************
115  *      MSVCRT_cosf (MSVCRT.@)
116  */
117 float CDECL MSVCRT_cosf( float x )
118 {
119   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
120   return cosf(x);
121 }
122
123 /*********************************************************************
124  *      MSVCRT_coshf (MSVCRT.@)
125  */
126 float CDECL MSVCRT_coshf( float x )
127 {
128   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
129   return coshf(x);
130 }
131
132 /*********************************************************************
133  *      MSVCRT_expf (MSVCRT.@)
134  */
135 float CDECL MSVCRT_expf( float x )
136 {
137   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
138   return expf(x);
139 }
140
141 /*********************************************************************
142  *      MSVCRT_fmodf (MSVCRT.@)
143  */
144 float CDECL MSVCRT_fmodf( float x, float y )
145 {
146   if (!finitef(x) || !finitef(y)) *MSVCRT__errno() = MSVCRT_EDOM;
147   return fmodf(x,y);
148 }
149
150 /*********************************************************************
151  *      MSVCRT_logf (MSVCRT.@)
152  */
153 float CDECL MSVCRT_logf( float x)
154 {
155   if (x < 0.0 || !finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
156   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
157   return logf(x);
158 }
159
160 /*********************************************************************
161  *      MSVCRT_log10f (MSVCRT.@)
162  */
163 float CDECL MSVCRT_log10f( float x )
164 {
165   if (x < 0.0 || !finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
166   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
167   return log10f(x);
168 }
169
170 /*********************************************************************
171  *      MSVCRT_powf (MSVCRT.@)
172  */
173 float CDECL MSVCRT_powf( float x, float y )
174 {
175   /* FIXME: If x < 0 and y is not integral, set EDOM */
176   float z = powf(x,y);
177   if (!finitef(z)) *MSVCRT__errno() = MSVCRT_EDOM;
178   return z;
179 }
180
181 /*********************************************************************
182  *      MSVCRT_sinf (MSVCRT.@)
183  */
184 float CDECL MSVCRT_sinf( float x )
185 {
186   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
187   return sinf(x);
188 }
189
190 /*********************************************************************
191  *      MSVCRT_sinhf (MSVCRT.@)
192  */
193 float CDECL MSVCRT_sinhf( float x )
194 {
195   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
196   return sinhf(x);
197 }
198
199 /*********************************************************************
200  *      MSVCRT_sqrtf (MSVCRT.@)
201  */
202 float CDECL MSVCRT_sqrtf( float x )
203 {
204   if (x < 0.0 || !finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
205   return sqrtf(x);
206 }
207
208 /*********************************************************************
209  *      MSVCRT_tanf (MSVCRT.@)
210  */
211 float CDECL MSVCRT_tanf( float x )
212 {
213   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
214   return tanf(x);
215 }
216
217 /*********************************************************************
218  *      MSVCRT_tanhf (MSVCRT.@)
219  */
220 float CDECL MSVCRT_tanhf( float x )
221 {
222   if (!finitef(x)) *MSVCRT__errno() = MSVCRT_EDOM;
223   return tanhf(x);
224 }
225
226 /*********************************************************************
227  *      ceilf (MSVCRT.@)
228  */
229 float CDECL MSVCRT_ceilf( float x )
230 {
231   return ceilf(x);
232 }
233
234 /*********************************************************************
235  *      floorf (MSVCRT.@)
236  */
237 float CDECL MSVCRT_floorf( float x )
238 {
239   return floorf(x);
240 }
241
242 /*********************************************************************
243  *      frexpf (MSVCRT.@)
244  */
245 float CDECL MSVCRT_frexpf( float x, int *exp )
246 {
247   return frexpf( x, exp );
248 }
249
250 /*********************************************************************
251  *      _scalbf (MSVCRT.@)
252  */
253 float CDECL MSVCRT__scalbf(float num, MSVCRT_long power)
254 {
255   if (!finitef(num)) *MSVCRT__errno() = MSVCRT_EDOM;
256   return ldexpf(num, power);
257 }
258
259 /*********************************************************************
260  *      modff (MSVCRT.@)
261  */
262 double CDECL MSVCRT_modff( float x, float *iptr )
263 {
264   return modff( x, iptr );
265 }
266
267 #endif
268
269 /*********************************************************************
270  *              MSVCRT_acos (MSVCRT.@)
271  */
272 double CDECL MSVCRT_acos( double x )
273 {
274   if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
275   /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
276    * asin() uses a similar construction. This is bad because as x gets nearer to
277    * 1 the error in the expression "1 - x^2" can get relatively large due to
278    * cancellation. The sqrt() makes things worse. A safer way to calculate
279    * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
280   return atan2(sqrt((1 - x) * (1 + x)), x);
281 }
282
283 /*********************************************************************
284  *              MSVCRT_asin (MSVCRT.@)
285  */
286 double CDECL MSVCRT_asin( double x )
287 {
288   if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
289   return atan2(x, sqrt((1 - x) * (1 + x)));
290 }
291
292 /*********************************************************************
293  *              MSVCRT_atan (MSVCRT.@)
294  */
295 double CDECL MSVCRT_atan( double x )
296 {
297   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
298   return atan(x);
299 }
300
301 /*********************************************************************
302  *              MSVCRT_atan2 (MSVCRT.@)
303  */
304 double CDECL MSVCRT_atan2( double x, double y )
305 {
306   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
307   return atan2(x,y);
308 }
309
310 /*********************************************************************
311  *              MSVCRT_cos (MSVCRT.@)
312  */
313 double CDECL MSVCRT_cos( double x )
314 {
315   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
316   return cos(x);
317 }
318
319 /*********************************************************************
320  *              MSVCRT_cosh (MSVCRT.@)
321  */
322 double CDECL MSVCRT_cosh( double x )
323 {
324   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
325   return cosh(x);
326 }
327
328 /*********************************************************************
329  *              MSVCRT_exp (MSVCRT.@)
330  */
331 double CDECL MSVCRT_exp( double x )
332 {
333   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
334   return exp(x);
335 }
336
337 /*********************************************************************
338  *              MSVCRT_fmod (MSVCRT.@)
339  */
340 double CDECL MSVCRT_fmod( double x, double y )
341 {
342   if (!finite(x) || !finite(y)) *MSVCRT__errno() = MSVCRT_EDOM;
343   return fmod(x,y);
344 }
345
346 /*********************************************************************
347  *              MSVCRT_log (MSVCRT.@)
348  */
349 double CDECL MSVCRT_log( double x)
350 {
351   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
352   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
353   return log(x);
354 }
355
356 /*********************************************************************
357  *              MSVCRT_log10 (MSVCRT.@)
358  */
359 double CDECL MSVCRT_log10( double x )
360 {
361   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
362   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
363   return log10(x);
364 }
365
366 /*********************************************************************
367  *              MSVCRT_pow (MSVCRT.@)
368  */
369 double CDECL MSVCRT_pow( double x, double y )
370 {
371   /* FIXME: If x < 0 and y is not integral, set EDOM */
372   double z = pow(x,y);
373   if (!finite(z)) *MSVCRT__errno() = MSVCRT_EDOM;
374   return z;
375 }
376
377 /*********************************************************************
378  *              MSVCRT_sin (MSVCRT.@)
379  */
380 double CDECL MSVCRT_sin( double x )
381 {
382   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
383   return sin(x);
384 }
385
386 /*********************************************************************
387  *              MSVCRT_sinh (MSVCRT.@)
388  */
389 double CDECL MSVCRT_sinh( double x )
390 {
391   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
392   return sinh(x);
393 }
394
395 /*********************************************************************
396  *              MSVCRT_sqrt (MSVCRT.@)
397  */
398 double CDECL MSVCRT_sqrt( double x )
399 {
400   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
401   return sqrt(x);
402 }
403
404 /*********************************************************************
405  *              MSVCRT_tan (MSVCRT.@)
406  */
407 double CDECL MSVCRT_tan( double x )
408 {
409   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
410   return tan(x);
411 }
412
413 /*********************************************************************
414  *              MSVCRT_tanh (MSVCRT.@)
415  */
416 double CDECL MSVCRT_tanh( double x )
417 {
418   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
419   return tanh(x);
420 }
421
422
423 #if defined(__GNUC__) && defined(__i386__)
424
425 #define FPU_DOUBLE(var) double var; \
426   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
427 #define FPU_DOUBLES(var1,var2) double var1,var2; \
428   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
429   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
430
431 /*********************************************************************
432  *              _CIacos (MSVCRT.@)
433  */
434 double CDECL _CIacos(void)
435 {
436   FPU_DOUBLE(x);
437   return MSVCRT_acos(x);
438 }
439
440 /*********************************************************************
441  *              _CIasin (MSVCRT.@)
442  */
443 double CDECL _CIasin(void)
444 {
445   FPU_DOUBLE(x);
446   return MSVCRT_asin(x);
447 }
448
449 /*********************************************************************
450  *              _CIatan (MSVCRT.@)
451  */
452 double CDECL _CIatan(void)
453 {
454   FPU_DOUBLE(x);
455   return MSVCRT_atan(x);
456 }
457
458 /*********************************************************************
459  *              _CIatan2 (MSVCRT.@)
460  */
461 double CDECL _CIatan2(void)
462 {
463   FPU_DOUBLES(x,y);
464   return MSVCRT_atan2(x,y);
465 }
466
467 /*********************************************************************
468  *              _CIcos (MSVCRT.@)
469  */
470 double CDECL _CIcos(void)
471 {
472   FPU_DOUBLE(x);
473   return MSVCRT_cos(x);
474 }
475
476 /*********************************************************************
477  *              _CIcosh (MSVCRT.@)
478  */
479 double CDECL _CIcosh(void)
480 {
481   FPU_DOUBLE(x);
482   return MSVCRT_cosh(x);
483 }
484
485 /*********************************************************************
486  *              _CIexp (MSVCRT.@)
487  */
488 double CDECL _CIexp(void)
489 {
490   FPU_DOUBLE(x);
491   return MSVCRT_exp(x);
492 }
493
494 /*********************************************************************
495  *              _CIfmod (MSVCRT.@)
496  */
497 double CDECL _CIfmod(void)
498 {
499   FPU_DOUBLES(x,y);
500   return MSVCRT_fmod(x,y);
501 }
502
503 /*********************************************************************
504  *              _CIlog (MSVCRT.@)
505  */
506 double CDECL _CIlog(void)
507 {
508   FPU_DOUBLE(x);
509   return MSVCRT_log(x);
510 }
511
512 /*********************************************************************
513  *              _CIlog10 (MSVCRT.@)
514  */
515 double CDECL _CIlog10(void)
516 {
517   FPU_DOUBLE(x);
518   return MSVCRT_log10(x);
519 }
520
521 /*********************************************************************
522  *              _CIpow (MSVCRT.@)
523  */
524 double CDECL _CIpow(void)
525 {
526   FPU_DOUBLES(x,y);
527   return MSVCRT_pow(x,y);
528 }
529
530 /*********************************************************************
531  *              _CIsin (MSVCRT.@)
532  */
533 double CDECL _CIsin(void)
534 {
535   FPU_DOUBLE(x);
536   return MSVCRT_sin(x);
537 }
538
539 /*********************************************************************
540  *              _CIsinh (MSVCRT.@)
541  */
542 double CDECL _CIsinh(void)
543 {
544   FPU_DOUBLE(x);
545   return MSVCRT_sinh(x);
546 }
547
548 /*********************************************************************
549  *              _CIsqrt (MSVCRT.@)
550  */
551 double CDECL _CIsqrt(void)
552 {
553   FPU_DOUBLE(x);
554   return MSVCRT_sqrt(x);
555 }
556
557 /*********************************************************************
558  *              _CItan (MSVCRT.@)
559  */
560 double CDECL _CItan(void)
561 {
562   FPU_DOUBLE(x);
563   return MSVCRT_tan(x);
564 }
565
566 /*********************************************************************
567  *              _CItanh (MSVCRT.@)
568  */
569 double CDECL _CItanh(void)
570 {
571   FPU_DOUBLE(x);
572   return MSVCRT_tanh(x);
573 }
574
575 #endif /* defined(__GNUC__) && defined(__i386__) */
576
577 /*********************************************************************
578  *              _fpclass (MSVCRT.@)
579  */
580 int CDECL MSVCRT__fpclass(double num)
581 {
582 #if defined(HAVE_FPCLASS) || defined(fpclass)
583   switch (fpclass( num ))
584   {
585 #ifdef FP_SNAN
586   case FP_SNAN:  return MSVCRT__FPCLASS_SNAN;
587 #endif
588 #ifdef FP_QNAN
589   case FP_QNAN:  return MSVCRT__FPCLASS_QNAN;
590 #endif
591 #ifdef FP_NINF
592   case FP_NINF:  return MSVCRT__FPCLASS_NINF;
593 #endif
594 #ifdef FP_PINF
595   case FP_PINF:  return MSVCRT__FPCLASS_PINF;
596 #endif
597 #ifdef FP_NDENORM
598   case FP_NDENORM: return MSVCRT__FPCLASS_ND;
599 #endif
600 #ifdef FP_PDENORM
601   case FP_PDENORM: return MSVCRT__FPCLASS_PD;
602 #endif
603 #ifdef FP_NZERO
604   case FP_NZERO: return MSVCRT__FPCLASS_NZ;
605 #endif
606 #ifdef FP_PZERO
607   case FP_PZERO: return MSVCRT__FPCLASS_PZ;
608 #endif
609 #ifdef FP_NNORM
610   case FP_NNORM: return MSVCRT__FPCLASS_NN;
611 #endif
612 #ifdef FP_PNORM
613   case FP_PNORM: return MSVCRT__FPCLASS_PN;
614 #endif
615   default: return MSVCRT__FPCLASS_PN;
616   }
617 #elif defined (fpclassify)
618   switch (fpclassify( num ))
619   {
620   case FP_NAN: return MSVCRT__FPCLASS_QNAN;
621   case FP_INFINITE: return signbit(num) ? MSVCRT__FPCLASS_NINF : MSVCRT__FPCLASS_PINF;
622   case FP_SUBNORMAL: return signbit(num) ?MSVCRT__FPCLASS_ND : MSVCRT__FPCLASS_PD;
623   case FP_ZERO: return signbit(num) ? MSVCRT__FPCLASS_NZ : MSVCRT__FPCLASS_PZ;
624   }
625   return signbit(num) ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN;
626 #else
627   if (!finite(num))
628     return MSVCRT__FPCLASS_QNAN;
629   return num == 0.0 ? MSVCRT__FPCLASS_PZ : (num < 0 ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN);
630 #endif
631 }
632
633 /*********************************************************************
634  *              _rotl (MSVCRT.@)
635  */
636 unsigned int CDECL _rotl(unsigned int num, int shift)
637 {
638   shift &= 31;
639   return (num << shift) | (num >> (32-shift));
640 }
641
642 /*********************************************************************
643  *              _lrotl (MSVCRT.@)
644  */
645 MSVCRT_ulong CDECL MSVCRT__lrotl(MSVCRT_ulong num, int shift)
646 {
647   shift &= 0x1f;
648   return (num << shift) | (num >> (32-shift));
649 }
650
651 /*********************************************************************
652  *              _lrotr (MSVCRT.@)
653  */
654 MSVCRT_ulong CDECL MSVCRT__lrotr(MSVCRT_ulong num, int shift)
655 {
656   shift &= 0x1f;
657   return (num >> shift) | (num << (32-shift));
658 }
659
660 /*********************************************************************
661  *              _rotr (MSVCRT.@)
662  */
663 unsigned int CDECL _rotr(unsigned int num, int shift)
664 {
665     shift &= 0x1f;
666     return (num >> shift) | (num << (32-shift));
667 }
668
669 /*********************************************************************
670  *              _rotl64 (MSVCRT.@)
671  */
672 unsigned __int64 CDECL _rotl64(unsigned __int64 num, int shift)
673 {
674   shift &= 63;
675   return (num << shift) | (num >> (64-shift));
676 }
677
678 /*********************************************************************
679  *              _rotr64 (MSVCRT.@)
680  */
681 unsigned __int64 CDECL _rotr64(unsigned __int64 num, int shift)
682 {
683     shift &= 63;
684     return (num >> shift) | (num << (64-shift));
685 }
686
687 /*********************************************************************
688  *              abs (MSVCRT.@)
689  */
690 int CDECL MSVCRT_abs( int n )
691 {
692     return n >= 0 ? n : -n;
693 }
694
695 /*********************************************************************
696  *              labs (MSVCRT.@)
697  */
698 MSVCRT_long CDECL MSVCRT_labs( MSVCRT_long n )
699 {
700     return n >= 0 ? n : -n;
701 }
702
703 /*********************************************************************
704  *              _abs64 (MSVCRT.@)
705  */
706 __int64 CDECL _abs64( __int64 n )
707 {
708     return n >= 0 ? n : -n;
709 }
710
711 /*********************************************************************
712  *              _logb (MSVCRT.@)
713  */
714 double CDECL MSVCRT__logb(double num)
715 {
716   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
717   return logb(num);
718 }
719
720 /*********************************************************************
721  *              _scalb (MSVCRT.@)
722  */
723 double CDECL MSVCRT__scalb(double num, MSVCRT_long power)
724 {
725   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
726   return ldexp(num, power);
727 }
728
729 /*********************************************************************
730  *              _hypot (MSVCRT.@)
731  */
732 double CDECL _hypot(double x, double y)
733 {
734   /* FIXME: errno handling */
735   return hypot( x, y );
736 }
737
738 /*********************************************************************
739  *      _hypotf (MSVCRT.@)
740  */
741 float CDECL MSVCRT__hypotf(float x, float y)
742 {
743   /* FIXME: errno handling */
744   return hypotf( x, y );
745 }
746
747 /*********************************************************************
748  *              ceil (MSVCRT.@)
749  */
750 double CDECL MSVCRT_ceil( double x )
751 {
752   return ceil(x);
753 }
754
755 /*********************************************************************
756  *              floor (MSVCRT.@)
757  */
758 double CDECL MSVCRT_floor( double x )
759 {
760   return floor(x);
761 }
762
763 /*********************************************************************
764  *              fabs (MSVCRT.@)
765  */
766 double CDECL MSVCRT_fabs( double x )
767 {
768   return fabs(x);
769 }
770
771 /*********************************************************************
772  *              frexp (MSVCRT.@)
773  */
774 double CDECL MSVCRT_frexp( double x, int *exp )
775 {
776   return frexp( x, exp );
777 }
778
779 /*********************************************************************
780  *              modf (MSVCRT.@)
781  */
782 double CDECL MSVCRT_modf( double x, double *iptr )
783 {
784   return modf( x, iptr );
785 }
786
787 /*********************************************************************
788  *              _matherr (MSVCRT.@)
789  */
790 int CDECL MSVCRT__matherr(struct MSVCRT__exception *e)
791 {
792   if (e)
793     TRACE("(%p = %d, %s, %g %g %g)\n",e, e->type, e->name, e->arg1, e->arg2,
794           e->retval);
795   else
796     TRACE("(null)\n");
797   if (MSVCRT_default_matherr_func)
798     return MSVCRT_default_matherr_func(e);
799   ERR(":Unhandled math error!\n");
800   return 0;
801 }
802
803 /*********************************************************************
804  *              __setusermatherr (MSVCRT.@)
805  */
806 void CDECL MSVCRT___setusermatherr(MSVCRT_matherr_func func)
807 {
808   MSVCRT_default_matherr_func = func;
809   TRACE(":new matherr handler %p\n", func);
810 }
811
812 /**********************************************************************
813  *              _statusfp2 (MSVCRT.@)
814  *
815  * Not exported by native msvcrt, added in msvcr80.
816  */
817 #if defined(__i386__) || defined(__x86_64__)
818 void CDECL _statusfp2( unsigned int *x86_sw, unsigned int *sse2_sw )
819 {
820 #ifdef __GNUC__
821     unsigned int flags;
822     unsigned long fpword;
823
824     if (x86_sw)
825     {
826         __asm__ __volatile__( "fstsw %0" : "=m" (fpword) );
827         flags = 0;
828         if (fpword & 0x1)  flags |= MSVCRT__SW_INVALID;
829         if (fpword & 0x2)  flags |= MSVCRT__SW_DENORMAL;
830         if (fpword & 0x4)  flags |= MSVCRT__SW_ZERODIVIDE;
831         if (fpword & 0x8)  flags |= MSVCRT__SW_OVERFLOW;
832         if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
833         if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
834         *x86_sw = flags;
835     }
836
837     if (!sse2_sw) return;
838
839     if (sse2_supported)
840     {
841         __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
842         flags = 0;
843         if (fpword & 0x1)  flags |= MSVCRT__SW_INVALID;
844         if (fpword & 0x2)  flags |= MSVCRT__SW_DENORMAL;
845         if (fpword & 0x4)  flags |= MSVCRT__SW_ZERODIVIDE;
846         if (fpword & 0x8)  flags |= MSVCRT__SW_OVERFLOW;
847         if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
848         if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
849         *sse2_sw = flags;
850     }
851     else *sse2_sw = 0;
852 #else
853     FIXME( "not implemented\n" );
854 #endif
855 }
856 #endif
857
858 /**********************************************************************
859  *              _statusfp (MSVCRT.@)
860  */
861 unsigned int CDECL _statusfp(void)
862 {
863 #if defined(__i386__) || defined(__x86_64__)
864     unsigned int x86_sw, sse2_sw;
865
866     _statusfp2( &x86_sw, &sse2_sw );
867     /* FIXME: there's no definition for ambiguous status, just return all status bits for now */
868     return x86_sw | sse2_sw;
869 #else
870     FIXME( "not implemented\n" );
871     return 0;
872 #endif
873 }
874
875 /*********************************************************************
876  *              _clearfp (MSVCRT.@)
877  */
878 unsigned int CDECL _clearfp(void)
879 {
880     unsigned int flags = 0;
881 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
882     unsigned long fpword;
883
884     __asm__ __volatile__( "fnstsw %0; fnclex" : "=m" (fpword) );
885     if (fpword & 0x1)  flags |= MSVCRT__SW_INVALID;
886     if (fpword & 0x2)  flags |= MSVCRT__SW_DENORMAL;
887     if (fpword & 0x4)  flags |= MSVCRT__SW_ZERODIVIDE;
888     if (fpword & 0x8)  flags |= MSVCRT__SW_OVERFLOW;
889     if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
890     if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
891
892     if (sse2_supported)
893     {
894         __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
895         if (fpword & 0x1)  flags |= MSVCRT__SW_INVALID;
896         if (fpword & 0x2)  flags |= MSVCRT__SW_DENORMAL;
897         if (fpword & 0x4)  flags |= MSVCRT__SW_ZERODIVIDE;
898         if (fpword & 0x8)  flags |= MSVCRT__SW_OVERFLOW;
899         if (fpword & 0x10) flags |= MSVCRT__SW_UNDERFLOW;
900         if (fpword & 0x20) flags |= MSVCRT__SW_INEXACT;
901         fpword &= ~0x3f;
902         __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
903     }
904 #else
905     FIXME( "not implemented\n" );
906 #endif
907     return flags;
908 }
909
910 /*********************************************************************
911  *              __fpecode (MSVCRT.@)
912  */
913 int * CDECL __fpecode(void)
914 {
915     return &msvcrt_get_thread_data()->fpecode;
916 }
917
918 /*********************************************************************
919  *              ldexp (MSVCRT.@)
920  */
921 double CDECL MSVCRT_ldexp(double num, MSVCRT_long exp)
922 {
923   double z = ldexp(num,exp);
924
925   if (!finite(z))
926     *MSVCRT__errno() = MSVCRT_ERANGE;
927   else if (z == 0 && signbit(z))
928     z = 0.0; /* Convert -0 -> +0 */
929   return z;
930 }
931
932 /*********************************************************************
933  *              _cabs (MSVCRT.@)
934  */
935 double CDECL MSVCRT__cabs(struct MSVCRT__complex num)
936 {
937   return sqrt(num.x * num.x + num.y * num.y);
938 }
939
940 /*********************************************************************
941  *              _chgsign (MSVCRT.@)
942  */
943 double CDECL MSVCRT__chgsign(double num)
944 {
945   /* FIXME: +-infinity,Nan not tested */
946   return -num;
947 }
948
949 /*********************************************************************
950  *              __control87_2 (MSVCRT.@)
951  *
952  * Not exported by native msvcrt, added in msvcr80.
953  */
954 #if defined(__i386__) || defined(__x86_64__)
955 int CDECL __control87_2( unsigned int newval, unsigned int mask,
956                          unsigned int *x86_cw, unsigned int *sse2_cw )
957 {
958 #ifdef __GNUC__
959     unsigned long fpword;
960     unsigned int flags;
961
962     if (x86_cw)
963     {
964         __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
965
966         /* Convert into mask constants */
967         flags = 0;
968         if (fpword & 0x1)  flags |= MSVCRT__EM_INVALID;
969         if (fpword & 0x2)  flags |= MSVCRT__EM_DENORMAL;
970         if (fpword & 0x4)  flags |= MSVCRT__EM_ZERODIVIDE;
971         if (fpword & 0x8)  flags |= MSVCRT__EM_OVERFLOW;
972         if (fpword & 0x10) flags |= MSVCRT__EM_UNDERFLOW;
973         if (fpword & 0x20) flags |= MSVCRT__EM_INEXACT;
974         switch (fpword & 0xc00)
975         {
976         case 0xc00: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
977         case 0x800: flags |= MSVCRT__RC_UP; break;
978         case 0x400: flags |= MSVCRT__RC_DOWN; break;
979         }
980         switch (fpword & 0x300)
981         {
982         case 0x0:   flags |= MSVCRT__PC_24; break;
983         case 0x200: flags |= MSVCRT__PC_53; break;
984         case 0x300: flags |= MSVCRT__PC_64; break;
985         }
986         if (fpword & 0x1000) flags |= MSVCRT__IC_AFFINE;
987
988         TRACE( "x86 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
989         if (mask)
990         {
991             flags = (flags & ~mask) | (newval & mask);
992
993             /* Convert (masked) value back to fp word */
994             fpword = 0;
995             if (flags & MSVCRT__EM_INVALID)    fpword |= 0x1;
996             if (flags & MSVCRT__EM_DENORMAL)   fpword |= 0x2;
997             if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x4;
998             if (flags & MSVCRT__EM_OVERFLOW)   fpword |= 0x8;
999             if (flags & MSVCRT__EM_UNDERFLOW)  fpword |= 0x10;
1000             if (flags & MSVCRT__EM_INEXACT)    fpword |= 0x20;
1001             switch (flags & MSVCRT__MCW_RC)
1002             {
1003             case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0xc00; break;
1004             case MSVCRT__RC_UP:                 fpword |= 0x800; break;
1005             case MSVCRT__RC_DOWN:               fpword |= 0x400; break;
1006             }
1007             switch (flags & MSVCRT__MCW_PC)
1008             {
1009             case MSVCRT__PC_64: fpword |= 0x300; break;
1010             case MSVCRT__PC_53: fpword |= 0x200; break;
1011             case MSVCRT__PC_24: fpword |= 0x0; break;
1012             }
1013             if (flags & MSVCRT__IC_AFFINE) fpword |= 0x1000;
1014
1015             __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1016         }
1017         *x86_cw = flags;
1018     }
1019
1020     if (!sse2_cw) return 1;
1021
1022     if (sse2_supported)
1023     {
1024         __asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
1025
1026         /* Convert into mask constants */
1027         flags = 0;
1028         if (fpword & 0x80)   flags |= MSVCRT__EM_INVALID;
1029         if (fpword & 0x100)  flags |= MSVCRT__EM_DENORMAL;
1030         if (fpword & 0x200)  flags |= MSVCRT__EM_ZERODIVIDE;
1031         if (fpword & 0x400)  flags |= MSVCRT__EM_OVERFLOW;
1032         if (fpword & 0x800)  flags |= MSVCRT__EM_UNDERFLOW;
1033         if (fpword & 0x1000) flags |= MSVCRT__EM_INEXACT;
1034         switch (fpword & 0x6000)
1035         {
1036         case 0x6000: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
1037         case 0x4000: flags |= MSVCRT__RC_UP; break;
1038         case 0x2000: flags |= MSVCRT__RC_DOWN; break;
1039         }
1040         switch (fpword & 0x8040)
1041         {
1042         case 0x0040: flags |= MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS; break;
1043         case 0x8000: flags |= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
1044         case 0x8040: flags |= MSVCRT__DN_FLUSH; break;
1045         }
1046
1047         TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
1048         if (mask)
1049         {
1050             flags = (flags & ~mask) | (newval & mask);
1051
1052             /* Convert (masked) value back to fp word */
1053             fpword = 0;
1054             if (flags & MSVCRT__EM_INVALID)    fpword |= 0x80;
1055             if (flags & MSVCRT__EM_DENORMAL)   fpword |= 0x100;
1056             if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
1057             if (flags & MSVCRT__EM_OVERFLOW)   fpword |= 0x400;
1058             if (flags & MSVCRT__EM_UNDERFLOW)  fpword |= 0x800;
1059             if (flags & MSVCRT__EM_INEXACT)    fpword |= 0x1000;
1060             switch (flags & MSVCRT__MCW_RC)
1061             {
1062             case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0x6000; break;
1063             case MSVCRT__RC_UP:                 fpword |= 0x4000; break;
1064             case MSVCRT__RC_DOWN:               fpword |= 0x2000; break;
1065             }
1066             switch (flags & MSVCRT__MCW_DN)
1067             {
1068             case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
1069             case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
1070             case MSVCRT__DN_FLUSH:                       fpword |= 0x8040; break;
1071             }
1072             __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
1073         }
1074         *sse2_cw = flags;
1075     }
1076     else *sse2_cw = 0;
1077
1078     return 1;
1079 #else
1080     FIXME( "not implemented\n" );
1081     return 0;
1082 #endif
1083 }
1084 #endif
1085
1086 /*********************************************************************
1087  *              _control87 (MSVCRT.@)
1088  */
1089 unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
1090 {
1091 #if defined(__i386__) || defined(__x86_64__)
1092     unsigned int x86_cw, sse2_cw;
1093
1094     __control87_2( newval, mask, &x86_cw, &sse2_cw );
1095
1096     if ((x86_cw ^ sse2_cw) & (MSVCRT__MCW_EM | MSVCRT__MCW_RC)) x86_cw |= MSVCRT__EM_AMBIGUOUS;
1097     return x86_cw;
1098 #else
1099     FIXME( "not implemented\n" );
1100     return 0;
1101 #endif
1102 }
1103
1104 /*********************************************************************
1105  *              _controlfp (MSVCRT.@)
1106  */
1107 unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
1108 {
1109   return _control87( newval, mask & ~MSVCRT__EM_DENORMAL );
1110 }
1111
1112 /*********************************************************************
1113  *              _set_controlfp (MSVCRT.@)
1114  */
1115 void CDECL _set_controlfp( unsigned int newval, unsigned int mask )
1116 {
1117     _controlfp( newval, mask );
1118 }
1119
1120 /*********************************************************************
1121  *              _controlfp_s (MSVCRT.@)
1122  */
1123 int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask)
1124 {
1125     static const unsigned int all_flags = (MSVCRT__MCW_EM | MSVCRT__MCW_IC | MSVCRT__MCW_RC |
1126                                            MSVCRT__MCW_PC | MSVCRT__MCW_DN);
1127     unsigned int val;
1128
1129     if (!MSVCRT_CHECK_PMT( !(newval & mask & ~all_flags) ))
1130     {
1131         if (cur) *cur = _controlfp( 0, 0 );  /* retrieve it anyway */
1132         *MSVCRT__errno() = MSVCRT_EINVAL;
1133         return MSVCRT_EINVAL;
1134     }
1135     val = _controlfp( newval, mask );
1136     if (cur) *cur = val;
1137     return 0;
1138 }
1139
1140 /*********************************************************************
1141  *              _copysign (MSVCRT.@)
1142  */
1143 double CDECL MSVCRT__copysign(double num, double sign)
1144 {
1145   /* FIXME: Behaviour for Nan/Inf? */
1146   if (sign < 0.0)
1147     return num < 0.0 ? num : -num;
1148   return num < 0.0 ? -num : num;
1149 }
1150
1151 /*********************************************************************
1152  *              _finite (MSVCRT.@)
1153  */
1154 int CDECL MSVCRT__finite(double num)
1155 {
1156   return (finite(num)?1:0); /* See comment for _isnan() */
1157 }
1158
1159 /*********************************************************************
1160  *              _fpreset (MSVCRT.@)
1161  */
1162 void CDECL _fpreset(void)
1163 {
1164 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1165     const unsigned int x86_cw = 0x27f;
1166     __asm__ __volatile__( "fninit; fldcw %0" : : "m" (x86_cw) );
1167     if (sse2_supported)
1168     {
1169         const unsigned long sse2_cw = 0x1f80;
1170         __asm__ __volatile__( "ldmxcsr %0" : : "m" (sse2_cw) );
1171     }
1172 #else
1173     FIXME( "not implemented\n" );
1174 #endif
1175 }
1176
1177 /*********************************************************************
1178  *              _isnan (MSVCRT.@)
1179  */
1180 INT CDECL MSVCRT__isnan(double num)
1181 {
1182   /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
1183    * Do the same, as the result may be used in calculations
1184    */
1185   return isnan(num) ? 1 : 0;
1186 }
1187
1188 /*********************************************************************
1189  *              _j0 (MSVCRT.@)
1190  */
1191 double CDECL MSVCRT__j0(double num)
1192 {
1193   /* FIXME: errno handling */
1194   return j0(num);
1195 }
1196
1197 /*********************************************************************
1198  *              _j1 (MSVCRT.@)
1199  */
1200 double CDECL MSVCRT__j1(double num)
1201 {
1202   /* FIXME: errno handling */
1203   return j1(num);
1204 }
1205
1206 /*********************************************************************
1207  *              _jn (MSVCRT.@)
1208  */
1209 double CDECL MSVCRT__jn(int n, double num)
1210 {
1211   /* FIXME: errno handling */
1212   return jn(n, num);
1213 }
1214
1215 /*********************************************************************
1216  *              _y0 (MSVCRT.@)
1217  */
1218 double CDECL MSVCRT__y0(double num)
1219 {
1220   double retval;
1221   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1222   retval  = y0(num);
1223   if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1224   {
1225     *MSVCRT__errno() = MSVCRT_EDOM;
1226     retval = sqrt(-1);
1227   }
1228   return retval;
1229 }
1230
1231 /*********************************************************************
1232  *              _y1 (MSVCRT.@)
1233  */
1234 double CDECL MSVCRT__y1(double num)
1235 {
1236   double retval;
1237   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1238   retval  = y1(num);
1239   if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1240   {
1241     *MSVCRT__errno() = MSVCRT_EDOM;
1242     retval = sqrt(-1);
1243   }
1244   return retval;
1245 }
1246
1247 /*********************************************************************
1248  *              _yn (MSVCRT.@)
1249  */
1250 double CDECL MSVCRT__yn(int order, double num)
1251 {
1252   double retval;
1253   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
1254   retval  = yn(order,num);
1255   if (MSVCRT__fpclass(retval) == MSVCRT__FPCLASS_NINF)
1256   {
1257     *MSVCRT__errno() = MSVCRT_EDOM;
1258     retval = sqrt(-1);
1259   }
1260   return retval;
1261 }
1262
1263 /*********************************************************************
1264  *              _nextafter (MSVCRT.@)
1265  */
1266 double CDECL MSVCRT__nextafter(double num, double next)
1267 {
1268   double retval;
1269   if (!finite(num) || !finite(next)) *MSVCRT__errno() = MSVCRT_EDOM;
1270   retval = nextafter(num,next);
1271   return retval;
1272 }
1273
1274 /*********************************************************************
1275  *              _ecvt (MSVCRT.@)
1276  */
1277 char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
1278 {
1279     int prec, len;
1280     thread_data_t *data = msvcrt_get_thread_data();
1281     /* FIXME: check better for overflow (native supports over 300 chars) */
1282     ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
1283                                       * 4 for exponent and one for
1284                                       * terminating '\0' */
1285     if (!data->efcvt_buffer)
1286         data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
1287
1288     if( number < 0) {
1289         *sign = TRUE;
1290         number = -number;
1291     } else
1292         *sign = FALSE;
1293     /* handle cases with zero ndigits or less */
1294     prec = ndigits;
1295     if( prec < 1) prec = 2;
1296     len = snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
1297     /* take the decimal "point away */
1298     if( prec != 1)
1299         memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
1300     /* take the exponential "e" out */
1301     data->efcvt_buffer[ prec] = '\0';
1302     /* read the exponent */
1303     sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
1304     (*decpt)++;
1305     /* adjust for some border cases */
1306     if( data->efcvt_buffer[0] == '0')/* value is zero */
1307         *decpt = 0;
1308     /* handle cases with zero ndigits or less */
1309     if( ndigits < 1){
1310         if( data->efcvt_buffer[ 0] >= '5')
1311             (*decpt)++;
1312         data->efcvt_buffer[ 0] = '\0';
1313     }
1314     TRACE("out=\"%s\"\n",data->efcvt_buffer);
1315     return data->efcvt_buffer;
1316 }
1317
1318 /*********************************************************************
1319  *              _ecvt_s (MSVCRT.@)
1320  */
1321 int CDECL _ecvt_s( char *buffer, MSVCRT_size_t length, double number, int ndigits, int *decpt, int *sign )
1322 {
1323     int prec, len;
1324     char *result;
1325     const char infret[] = "1#INF";
1326
1327     if(!MSVCRT_CHECK_PMT(buffer != NULL) || !MSVCRT_CHECK_PMT(decpt != NULL) || !MSVCRT_CHECK_PMT(sign != NULL))
1328     {
1329         *MSVCRT__errno() = MSVCRT_EINVAL;
1330         return MSVCRT_EINVAL;
1331     }
1332     if(!MSVCRT_CHECK_PMT(length > 2) || !MSVCRT_CHECK_PMT(ndigits < (int)length - 1))
1333     {
1334         *MSVCRT__errno() = MSVCRT_ERANGE;
1335         return MSVCRT_ERANGE;
1336     }
1337
1338     /* special case - inf */
1339     if(number == HUGE_VAL || number == -HUGE_VAL)
1340     {
1341         memset(buffer, '0', ndigits);
1342         memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
1343         buffer[ndigits] = '\0';
1344         (*decpt) = 1;
1345         if(number == -HUGE_VAL)
1346             (*sign) = 1;
1347         else
1348             (*sign) = 0;
1349         return 0;
1350     }
1351     /* handle cases with zero ndigits or less */
1352     prec = ndigits;
1353     if( prec < 1) prec = 2;
1354     result = MSVCRT_malloc(prec + 7);
1355
1356     if( number < 0) {
1357         *sign = TRUE;
1358         number = -number;
1359     } else
1360         *sign = FALSE;
1361     len = snprintf(result, prec + 7, "%.*le", prec - 1, number);
1362     /* take the decimal "point away */
1363     if( prec != 1)
1364         memmove( result + 1, result + 2, len - 1 );
1365     /* take the exponential "e" out */
1366     result[ prec] = '\0';
1367     /* read the exponent */
1368     sscanf( result + prec + 1, "%d", decpt);
1369     (*decpt)++;
1370     /* adjust for some border cases */
1371     if( result[0] == '0')/* value is zero */
1372         *decpt = 0;
1373     /* handle cases with zero ndigits or less */
1374     if( ndigits < 1){
1375         if( result[ 0] >= '5')
1376             (*decpt)++;
1377         result[ 0] = '\0';
1378     }
1379     memcpy( buffer, result, max(ndigits + 1, 1) );
1380     MSVCRT_free( result );
1381     return 0;
1382 }
1383
1384 /***********************************************************************
1385  *              _fcvt  (MSVCRT.@)
1386  */
1387 char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
1388 {
1389     thread_data_t *data = msvcrt_get_thread_data();
1390     int stop, dec1, dec2;
1391     char *ptr1, *ptr2, *first;
1392     char buf[80]; /* ought to be enough */
1393
1394     if (!data->efcvt_buffer)
1395         data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
1396
1397     if (number < 0)
1398     {
1399         *sign = 1;
1400         number = -number;
1401     } else *sign = 0;
1402
1403     snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1404     ptr1 = buf;
1405     ptr2 = data->efcvt_buffer;
1406     first = NULL;
1407     dec1 = 0;
1408     dec2 = 0;
1409
1410     /* For numbers below the requested resolution, work out where
1411        the decimal point will be rather than finding it in the string */
1412     if (number < 1.0 && number > 0.0) {
1413         dec2 = log10(number + 1e-10);
1414         if (-dec2 <= ndigits) dec2 = 0;
1415     }
1416
1417     /* If requested digits is zero or less, we will need to truncate
1418      * the returned string */
1419     if (ndigits < 1) {
1420         stop = strlen(buf) + ndigits;
1421     } else {
1422         stop = strlen(buf);
1423     }
1424
1425     while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1426     while (*ptr1 != '\0' && *ptr1 != '.') {
1427         if (!first) first = ptr2;
1428         if ((ptr1 - buf) < stop) {
1429             *ptr2++ = *ptr1++;
1430         } else {
1431             ptr1++;
1432         }
1433         dec1++;
1434     }
1435
1436     if (ndigits > 0) {
1437         ptr1++;
1438         if (!first) {
1439             while (*ptr1 == '0') { /* Process leading zeroes */
1440                 *ptr2++ = *ptr1++;
1441                 dec1--;
1442             }
1443         }
1444         while (*ptr1 != '\0') {
1445             if (!first) first = ptr2;
1446             *ptr2++ = *ptr1++;
1447         }
1448     }
1449
1450     *ptr2 = '\0';
1451
1452     /* We never found a non-zero digit, then our number is either
1453      * smaller than the requested precision, or 0.0 */
1454     if (!first) {
1455         if (number > 0.0) {
1456             first = ptr2;
1457         } else {
1458             first = data->efcvt_buffer;
1459             dec1 = 0;
1460         }
1461     }
1462
1463     *decpt = dec2 ? dec2 : dec1;
1464     return first;
1465 }
1466
1467 /***********************************************************************
1468  *              _fcvt_s  (MSVCRT.@)
1469  */
1470 int CDECL _fcvt_s(char* outbuffer, MSVCRT_size_t size, double number, int ndigits, int *decpt, int *sign)
1471 {
1472     int stop, dec1, dec2;
1473     char *ptr1, *ptr2, *first;
1474     char buf[80]; /* ought to be enough */
1475
1476     if (!outbuffer || !decpt || !sign || size == 0)
1477     {
1478         *MSVCRT__errno() = MSVCRT_EINVAL;
1479         return MSVCRT_EINVAL;
1480     }
1481
1482     if (number < 0)
1483     {
1484         *sign = 1;
1485         number = -number;
1486     } else *sign = 0;
1487
1488     snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
1489     ptr1 = buf;
1490     ptr2 = outbuffer;
1491     first = NULL;
1492     dec1 = 0;
1493     dec2 = 0;
1494
1495     /* For numbers below the requested resolution, work out where
1496        the decimal point will be rather than finding it in the string */
1497     if (number < 1.0 && number > 0.0) {
1498         dec2 = log10(number + 1e-10);
1499         if (-dec2 <= ndigits) dec2 = 0;
1500     }
1501
1502     /* If requested digits is zero or less, we will need to truncate
1503      * the returned string */
1504     if (ndigits < 1) {
1505         stop = strlen(buf) + ndigits;
1506     } else {
1507         stop = strlen(buf);
1508     }
1509
1510     while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
1511     while (*ptr1 != '\0' && *ptr1 != '.') {
1512         if (!first) first = ptr2;
1513         if ((ptr1 - buf) < stop) {
1514             if (size > 1) {
1515                 *ptr2++ = *ptr1++;
1516                 size--;
1517             }
1518         } else {
1519             ptr1++;
1520         }
1521         dec1++;
1522     }
1523
1524     if (ndigits > 0) {
1525         ptr1++;
1526         if (!first) {
1527             while (*ptr1 == '0') { /* Process leading zeroes */
1528                 if (number == 0.0 && size > 1) {
1529                     *ptr2++ = '0';
1530                     size--;
1531                 }
1532                 ptr1++;
1533                 dec1--;
1534             }
1535         }
1536         while (*ptr1 != '\0') {
1537             if (!first) first = ptr2;
1538             if (size > 1) {
1539                 *ptr2++ = *ptr1++;
1540                 size--;
1541             }
1542         }
1543     }
1544
1545     *ptr2 = '\0';
1546
1547     /* We never found a non-zero digit, then our number is either
1548      * smaller than the requested precision, or 0.0 */
1549     if (!first && (number <= 0.0))
1550         dec1 = 0;
1551
1552     *decpt = dec2 ? dec2 : dec1;
1553     return 0;
1554 }
1555
1556 /***********************************************************************
1557  *              _gcvt  (MSVCRT.@)
1558  */
1559 char * CDECL _gcvt( double number, int ndigit, char *buff )
1560 {
1561     if(!buff) {
1562         *MSVCRT__errno() = MSVCRT_EINVAL;
1563         return NULL;
1564     }
1565
1566     if(ndigit < 0) {
1567         *MSVCRT__errno() = MSVCRT_ERANGE;
1568         return NULL;
1569     }
1570
1571     MSVCRT_sprintf(buff, "%.*g", ndigit, number);
1572     return buff;
1573 }
1574
1575 /***********************************************************************
1576  *              _gcvt_s  (MSVCRT.@)
1577  */
1578 int CDECL _gcvt_s(char *buff, MSVCRT_size_t size, double number, int digits)
1579 {
1580     int len;
1581
1582     if(!buff) {
1583         *MSVCRT__errno() = MSVCRT_EINVAL;
1584         return MSVCRT_EINVAL;
1585     }
1586
1587     if( digits<0 || digits>=size) {
1588         if(size)
1589             buff[0] = '\0';
1590
1591         *MSVCRT__errno() = MSVCRT_ERANGE;
1592         return MSVCRT_ERANGE;
1593     }
1594
1595     len = MSVCRT__scprintf("%.*g", digits, number);
1596     if(len > size) {
1597         buff[0] = '\0';
1598         *MSVCRT__errno() = MSVCRT_ERANGE;
1599         return MSVCRT_ERANGE;
1600     }
1601
1602     MSVCRT_sprintf(buff, "%.*g", digits, number);
1603     return 0;
1604 }
1605
1606 #include <stdlib.h> /* div_t, ldiv_t */
1607
1608 /*********************************************************************
1609  *              div (MSVCRT.@)
1610  * VERSION
1611  *      [i386] Windows binary compatible - returns the struct in eax/edx.
1612  */
1613 #ifdef __i386__
1614 unsigned __int64 CDECL MSVCRT_div(int num, int denom)
1615 {
1616   div_t dt = div(num,denom);
1617   return ((unsigned __int64)dt.rem << 32) | (unsigned int)dt.quot;
1618 }
1619 #else
1620 /*********************************************************************
1621  *              div (MSVCRT.@)
1622  * VERSION
1623  *      [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1624  */
1625 MSVCRT_div_t CDECL MSVCRT_div(int num, int denom)
1626 {
1627   div_t dt = div(num,denom);
1628   MSVCRT_div_t     ret;
1629   ret.quot = dt.quot;
1630   ret.rem = dt.rem;
1631
1632   return ret;
1633
1634 }
1635 #endif /* ifdef __i386__ */
1636
1637
1638 /*********************************************************************
1639  *              ldiv (MSVCRT.@)
1640  * VERSION
1641  *      [i386] Windows binary compatible - returns the struct in eax/edx.
1642  */
1643 #ifdef __i386__
1644 unsigned __int64 CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1645 {
1646   ldiv_t ldt = ldiv(num,denom);
1647   return ((unsigned __int64)ldt.rem << 32) | (MSVCRT_ulong)ldt.quot;
1648 }
1649 #else
1650 /*********************************************************************
1651  *              ldiv (MSVCRT.@)
1652  * VERSION
1653  *      [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1654  */
1655 MSVCRT_ldiv_t CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1656 {
1657   ldiv_t result = ldiv(num,denom);
1658
1659   MSVCRT_ldiv_t ret;
1660   ret.quot = result.quot;
1661   ret.rem = result.rem;
1662
1663   return ret;
1664 }
1665 #endif /* ifdef __i386__ */
1666
1667 #ifdef __i386__
1668
1669 /*********************************************************************
1670  *              _adjust_fdiv (MSVCRT.@)
1671  * Used by the MSVC compiler to work around the Pentium FDIV bug.
1672  */
1673 int MSVCRT__adjust_fdiv = 0;
1674
1675 /***********************************************************************
1676  *              _adj_fdiv_m16i (MSVCRT.@)
1677  *
1678  * NOTE
1679  *    I _think_ this function is intended to work around the Pentium
1680  *    fdiv bug.
1681  */
1682 void __stdcall _adj_fdiv_m16i( short arg )
1683 {
1684   TRACE("(): stub\n");
1685 }
1686
1687 /***********************************************************************
1688  *              _adj_fdiv_m32 (MSVCRT.@)
1689  *
1690  * NOTE
1691  *    I _think_ this function is intended to work around the Pentium
1692  *    fdiv bug.
1693  */
1694 void __stdcall _adj_fdiv_m32( unsigned int arg )
1695 {
1696   TRACE("(): stub\n");
1697 }
1698
1699 /***********************************************************************
1700  *              _adj_fdiv_m32i (MSVCRT.@)
1701  *
1702  * NOTE
1703  *    I _think_ this function is intended to work around the Pentium
1704  *    fdiv bug.
1705  */
1706 void __stdcall _adj_fdiv_m32i( int arg )
1707 {
1708   TRACE("(): stub\n");
1709 }
1710
1711 /***********************************************************************
1712  *              _adj_fdiv_m64 (MSVCRT.@)
1713  *
1714  * NOTE
1715  *    I _think_ this function is intended to work around the Pentium
1716  *    fdiv bug.
1717  */
1718 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
1719 {
1720   TRACE("(): stub\n");
1721 }
1722
1723 /***********************************************************************
1724  *              _adj_fdiv_r (MSVCRT.@)
1725  * FIXME
1726  *    This function is likely to have the wrong number of arguments.
1727  *
1728  * NOTE
1729  *    I _think_ this function is intended to work around the Pentium
1730  *    fdiv bug.
1731  */
1732 void _adj_fdiv_r(void)
1733 {
1734   TRACE("(): stub\n");
1735 }
1736
1737 /***********************************************************************
1738  *              _adj_fdivr_m16i (MSVCRT.@)
1739  *
1740  * NOTE
1741  *    I _think_ this function is intended to work around the Pentium
1742  *    fdiv bug.
1743  */
1744 void __stdcall _adj_fdivr_m16i( short arg )
1745 {
1746   TRACE("(): stub\n");
1747 }
1748
1749 /***********************************************************************
1750  *              _adj_fdivr_m32 (MSVCRT.@)
1751  *
1752  * NOTE
1753  *    I _think_ this function is intended to work around the Pentium
1754  *    fdiv bug.
1755  */
1756 void __stdcall _adj_fdivr_m32( unsigned int arg )
1757 {
1758   TRACE("(): stub\n");
1759 }
1760
1761 /***********************************************************************
1762  *              _adj_fdivr_m32i (MSVCRT.@)
1763  *
1764  * NOTE
1765  *    I _think_ this function is intended to work around the Pentium
1766  *    fdiv bug.
1767  */
1768 void __stdcall _adj_fdivr_m32i( int arg )
1769 {
1770   TRACE("(): stub\n");
1771 }
1772
1773 /***********************************************************************
1774  *              _adj_fdivr_m64 (MSVCRT.@)
1775  *
1776  * NOTE
1777  *    I _think_ this function is intended to work around the Pentium
1778  *    fdiv bug.
1779  */
1780 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
1781 {
1782   TRACE("(): stub\n");
1783 }
1784
1785 /***********************************************************************
1786  *              _adj_fpatan (MSVCRT.@)
1787  * FIXME
1788  *    This function is likely to have the wrong number of arguments.
1789  *
1790  * NOTE
1791  *    I _think_ this function is intended to work around the Pentium
1792  *    fdiv bug.
1793  */
1794 void _adj_fpatan(void)
1795 {
1796   TRACE("(): stub\n");
1797 }
1798
1799 /***********************************************************************
1800  *              _adj_fprem (MSVCRT.@)
1801  * FIXME
1802  *    This function is likely to have the wrong number of arguments.
1803  *
1804  * NOTE
1805  *    I _think_ this function is intended to work around the Pentium
1806  *    fdiv bug.
1807  */
1808 void _adj_fprem(void)
1809 {
1810   TRACE("(): stub\n");
1811 }
1812
1813 /***********************************************************************
1814  *              _adj_fprem1 (MSVCRT.@)
1815  * FIXME
1816  *    This function is likely to have the wrong number of arguments.
1817  *
1818  * NOTE
1819  *    I _think_ this function is intended to work around the Pentium
1820  *    fdiv bug.
1821  */
1822 void _adj_fprem1(void)
1823 {
1824   TRACE("(): stub\n");
1825 }
1826
1827 /***********************************************************************
1828  *              _adj_fptan (MSVCRT.@)
1829  * FIXME
1830  *    This function is likely to have the wrong number of arguments.
1831  *
1832  * NOTE
1833  *    I _think_ this function is intended to work around the Pentium
1834  *    fdiv bug.
1835  */
1836 void _adj_fptan(void)
1837 {
1838   TRACE("(): stub\n");
1839 }
1840
1841 /***********************************************************************
1842  *              _safe_fdiv (MSVCRT.@)
1843  * FIXME
1844  *    This function is likely to have the wrong number of arguments.
1845  *
1846  * NOTE
1847  *    I _think_ this function is intended to work around the Pentium
1848  *    fdiv bug.
1849  */
1850 void _safe_fdiv(void)
1851 {
1852   TRACE("(): stub\n");
1853 }
1854
1855 /***********************************************************************
1856  *              _safe_fdivr (MSVCRT.@)
1857  * FIXME
1858  *    This function is likely to have the wrong number of arguments.
1859  *
1860  * NOTE
1861  *    I _think_ this function is intended to work around the Pentium
1862  *    fdiv bug.
1863  */
1864 void _safe_fdivr(void)
1865 {
1866   TRACE("(): stub\n");
1867 }
1868
1869 /***********************************************************************
1870  *              _safe_fprem (MSVCRT.@)
1871  * FIXME
1872  *    This function is likely to have the wrong number of arguments.
1873  *
1874  * NOTE
1875  *    I _think_ this function is intended to work around the Pentium
1876  *    fdiv bug.
1877  */
1878 void _safe_fprem(void)
1879 {
1880   TRACE("(): stub\n");
1881 }
1882
1883 /***********************************************************************
1884  *              _safe_fprem1 (MSVCRT.@)
1885  *
1886  * FIXME
1887  *    This function is likely to have the wrong number of arguments.
1888  *
1889  * NOTE
1890  *    I _think_ this function is intended to work around the Pentium
1891  *    fdiv bug.
1892  */
1893 void _safe_fprem1(void)
1894 {
1895   TRACE("(): stub\n");
1896 }
1897
1898 /***********************************************************************
1899  *              __libm_sse2_acos   (MSVCRT.@)
1900  */
1901 void __cdecl __libm_sse2_acos(void)
1902 {
1903     double d;
1904     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
1905     d = acos( d );
1906     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
1907 }
1908
1909 /***********************************************************************
1910  *              __libm_sse2_acosf   (MSVCRT.@)
1911  */
1912 void __cdecl __libm_sse2_acosf(void)
1913 {
1914     float f;
1915     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
1916     f = acosf( f );
1917     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
1918 }
1919
1920 /***********************************************************************
1921  *              __libm_sse2_asin   (MSVCRT.@)
1922  */
1923 void __cdecl __libm_sse2_asin(void)
1924 {
1925     double d;
1926     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
1927     d = asin( d );
1928     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
1929 }
1930
1931 /***********************************************************************
1932  *              __libm_sse2_asinf   (MSVCRT.@)
1933  */
1934 void __cdecl __libm_sse2_asinf(void)
1935 {
1936     float f;
1937     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
1938     f = asinf( f );
1939     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
1940 }
1941
1942 /***********************************************************************
1943  *              __libm_sse2_atan   (MSVCRT.@)
1944  */
1945 void __cdecl __libm_sse2_atan(void)
1946 {
1947     double d;
1948     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
1949     d = atan( d );
1950     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
1951 }
1952
1953 /***********************************************************************
1954  *              __libm_sse2_atan2   (MSVCRT.@)
1955  */
1956 void __cdecl __libm_sse2_atan2(void)
1957 {
1958     double d1, d2;
1959     __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
1960     d1 = atan2( d1, d2 );
1961     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
1962 }
1963
1964 /***********************************************************************
1965  *              __libm_sse2_atanf   (MSVCRT.@)
1966  */
1967 void __cdecl __libm_sse2_atanf(void)
1968 {
1969     float f;
1970     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
1971     f = atanf( f );
1972     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
1973 }
1974
1975 /***********************************************************************
1976  *              __libm_sse2_cos   (MSVCRT.@)
1977  */
1978 void __cdecl __libm_sse2_cos(void)
1979 {
1980     double d;
1981     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
1982     d = cos( d );
1983     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
1984 }
1985
1986 /***********************************************************************
1987  *              __libm_sse2_cosf   (MSVCRT.@)
1988  */
1989 void __cdecl __libm_sse2_cosf(void)
1990 {
1991     float f;
1992     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
1993     f = cosf( f );
1994     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
1995 }
1996
1997 /***********************************************************************
1998  *              __libm_sse2_exp   (MSVCRT.@)
1999  */
2000 void __cdecl __libm_sse2_exp(void)
2001 {
2002     double d;
2003     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2004     d = exp( d );
2005     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2006 }
2007
2008 /***********************************************************************
2009  *              __libm_sse2_expf   (MSVCRT.@)
2010  */
2011 void __cdecl __libm_sse2_expf(void)
2012 {
2013     float f;
2014     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2015     f = expf( f );
2016     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2017 }
2018
2019 /***********************************************************************
2020  *              __libm_sse2_log   (MSVCRT.@)
2021  */
2022 void __cdecl __libm_sse2_log(void)
2023 {
2024     double d;
2025     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2026     d = log( d );
2027     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2028 }
2029
2030 /***********************************************************************
2031  *              __libm_sse2_log10   (MSVCRT.@)
2032  */
2033 void __cdecl __libm_sse2_log10(void)
2034 {
2035     double d;
2036     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2037     d = log10( d );
2038     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2039 }
2040
2041 /***********************************************************************
2042  *              __libm_sse2_log10f   (MSVCRT.@)
2043  */
2044 void __cdecl __libm_sse2_log10f(void)
2045 {
2046     float f;
2047     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2048     f = log10f( f );
2049     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2050 }
2051
2052 /***********************************************************************
2053  *              __libm_sse2_logf   (MSVCRT.@)
2054  */
2055 void __cdecl __libm_sse2_logf(void)
2056 {
2057     float f;
2058     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2059     f = logf( f );
2060     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2061 }
2062
2063 /***********************************************************************
2064  *              __libm_sse2_pow   (MSVCRT.@)
2065  */
2066 void __cdecl __libm_sse2_pow(void)
2067 {
2068     double d1, d2;
2069     __asm__ __volatile__( "movq %%xmm0,%0; movq %%xmm1,%1 " : "=m" (d1), "=m" (d2) );
2070     d1 = pow( d1, d2 );
2071     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d1) );
2072 }
2073
2074 /***********************************************************************
2075  *              __libm_sse2_powf   (MSVCRT.@)
2076  */
2077 void __cdecl __libm_sse2_powf(void)
2078 {
2079     float f1, f2;
2080     __asm__ __volatile__( "movd %%xmm0,%0; movd %%xmm1,%1" : "=g" (f1), "=g" (f2) );
2081     f1 = powf( f1, f2 );
2082     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f1) );
2083 }
2084
2085 /***********************************************************************
2086  *              __libm_sse2_sin   (MSVCRT.@)
2087  */
2088 void __cdecl __libm_sse2_sin(void)
2089 {
2090     double d;
2091     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2092     d = sin( d );
2093     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2094 }
2095
2096 /***********************************************************************
2097  *              __libm_sse2_sinf   (MSVCRT.@)
2098  */
2099 void __cdecl __libm_sse2_sinf(void)
2100 {
2101     float f;
2102     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2103     f = sinf( f );
2104     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2105 }
2106
2107 /***********************************************************************
2108  *              __libm_sse2_tan   (MSVCRT.@)
2109  */
2110 void __cdecl __libm_sse2_tan(void)
2111 {
2112     double d;
2113     __asm__ __volatile__( "movq %%xmm0,%0" : "=m" (d) );
2114     d = tan( d );
2115     __asm__ __volatile__( "movq %0,%%xmm0" : : "m" (d) );
2116 }
2117
2118 /***********************************************************************
2119  *              __libm_sse2_tanf   (MSVCRT.@)
2120  */
2121 void __cdecl __libm_sse2_tanf(void)
2122 {
2123     float f;
2124     __asm__ __volatile__( "movd %%xmm0,%0" : "=g" (f) );
2125     f = tanf( f );
2126     __asm__ __volatile__( "movd %0,%%xmm0" : : "g" (f) );
2127 }
2128
2129 #endif  /* __i386__ */