Split the MSVCRT implementation headers from the public headers.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 (*MSVCRT_matherr_func)(struct MSVCRT__exception *);
51
52 static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
53
54 #if defined(__GNUC__) && defined(__i386__)
55
56 #define FPU_DOUBLE(var) double var; \
57   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
58 #define FPU_DOUBLES(var1,var2) double var1,var2; \
59   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
60   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
61
62 /*********************************************************************
63  *              _CIacos (MSVCRT.@)
64  */
65 double _CIacos(void)
66 {
67   FPU_DOUBLE(x);
68   if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
69   return acos(x);
70 }
71
72 /*********************************************************************
73  *              _CIasin (MSVCRT.@)
74  */
75 double _CIasin(void)
76 {
77   FPU_DOUBLE(x);
78   if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
79   return asin(x);
80 }
81
82 /*********************************************************************
83  *              _CIatan (MSVCRT.@)
84  */
85 double _CIatan(void)
86 {
87   FPU_DOUBLE(x);
88   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
89   return atan(x);
90 }
91
92 /*********************************************************************
93  *              _CIatan2 (MSVCRT.@)
94  */
95 double _CIatan2(void)
96 {
97   FPU_DOUBLES(x,y);
98   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
99   return atan2(x,y);
100 }
101
102 /*********************************************************************
103  *              _CIcos (MSVCRT.@)
104  */
105 double _CIcos(void)
106 {
107   FPU_DOUBLE(x);
108   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
109   return cos(x);
110 }
111
112 /*********************************************************************
113  *              _CIcosh (MSVCRT.@)
114  */
115 double _CIcosh(void)
116 {
117   FPU_DOUBLE(x);
118   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
119   return cosh(x);
120 }
121
122 /*********************************************************************
123  *              _CIexp (MSVCRT.@)
124  */
125 double _CIexp(void)
126 {
127   FPU_DOUBLE(x);
128   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
129   return exp(x);
130 }
131
132 /*********************************************************************
133  *              _CIfmod (MSVCRT.@)
134  */
135 double _CIfmod(void)
136 {
137   FPU_DOUBLES(x,y);
138   if (!finite(x) || !finite(y)) *MSVCRT__errno() = MSVCRT_EDOM;
139   return fmod(x,y);
140 }
141
142 /*********************************************************************
143  *              _CIlog (MSVCRT.@)
144  */
145 double _CIlog(void)
146 {
147   FPU_DOUBLE(x);
148   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
149   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
150   return log(x);
151 }
152
153 /*********************************************************************
154  *              _CIlog10 (MSVCRT.@)
155  */
156 double _CIlog10(void)
157 {
158   FPU_DOUBLE(x);
159   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
160   if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
161   return log10(x);
162 }
163
164 /*********************************************************************
165  *              _CIpow (MSVCRT.@)
166  */
167 double _CIpow(void)
168 {
169   double z;
170   FPU_DOUBLES(x,y);
171   /* FIXME: If x < 0 and y is not integral, set EDOM */
172   z = pow(x,y);
173   if (!finite(z)) *MSVCRT__errno() = MSVCRT_EDOM;
174   return z;
175 }
176
177 /*********************************************************************
178  *              _CIsin (MSVCRT.@)
179  */
180 double _CIsin(void)
181 {
182   FPU_DOUBLE(x);
183   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
184   return sin(x);
185 }
186
187 /*********************************************************************
188  *              _CIsinh (MSVCRT.@)
189  */
190 double _CIsinh(void)
191 {
192   FPU_DOUBLE(x);
193   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
194   return sinh(x);
195 }
196
197 /*********************************************************************
198  *              _CIsqrt (MSVCRT.@)
199  */
200 double _CIsqrt(void)
201 {
202   FPU_DOUBLE(x);
203   if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
204   return sqrt(x);
205 }
206
207 /*********************************************************************
208  *              _CItan (MSVCRT.@)
209  */
210 double _CItan(void)
211 {
212   FPU_DOUBLE(x);
213   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
214   return tan(x);
215 }
216
217 /*********************************************************************
218  *              _CItanh (MSVCRT.@)
219  */
220 double _CItanh(void)
221 {
222   FPU_DOUBLE(x);
223   if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
224   return tanh(x);
225 }
226
227 #else /* defined(__GNUC__) && defined(__i386__) */
228
229 /* The above cannot be called on non x86 platforms, stub them for linking */
230
231 #define IX86_ONLY(func) double func(void) { return 0.0; }
232
233 IX86_ONLY(_CIacos)
234 IX86_ONLY(_CIasin)
235 IX86_ONLY(_CIatan)
236 IX86_ONLY(_CIatan2)
237 IX86_ONLY(_CIcos)
238 IX86_ONLY(_CIcosh)
239 IX86_ONLY(_CIexp)
240 IX86_ONLY(_CIfmod)
241 IX86_ONLY(_CIlog)
242 IX86_ONLY(_CIlog10)
243 IX86_ONLY(_CIpow)
244 IX86_ONLY(_CIsin)
245 IX86_ONLY(_CIsinh)
246 IX86_ONLY(_CIsqrt)
247 IX86_ONLY(_CItan)
248 IX86_ONLY(_CItanh)
249
250 #endif /* defined(__GNUC__) && defined(__i386__) */
251
252 /*********************************************************************
253  *              _fpclass (MSVCRT.@)
254  */
255 int _fpclass(double num)
256 {
257 #if defined(HAVE_FPCLASS) || defined(fpclass)
258   switch (fpclass( num ))
259   {
260 #ifdef FP_SNAN
261   case FP_SNAN:  return MSVCRT__FPCLASS_SNAN;
262 #endif
263 #ifdef FP_QNAN
264   case FP_QNAN:  return MSVCRT__FPCLASS_QNAN;
265 #endif
266 #ifdef FP_NINF
267   case FP_NINF:  return MSVCRT__FPCLASS_NINF;
268 #endif
269 #ifdef FP_PINF
270   case FP_PINF:  return MSVCRT__FPCLASS_PINF;
271 #endif
272 #ifdef FP_NDENORM
273   case FP_NDENORM: return MSVCRT__FPCLASS_ND;
274 #endif
275 #ifdef FP_PDENORM
276   case FP_PDENORM: return MSVCRT__FPCLASS_PD;
277 #endif
278 #ifdef FP_NZERO
279   case FP_NZERO: return MSVCRT__FPCLASS_NZ;
280 #endif
281 #ifdef FP_PZERO
282   case FP_PZERO: return MSVCRT__FPCLASS_PZ;
283 #endif
284 #ifdef FP_NNORM
285   case FP_NNORM: return MSVCRT__FPCLASS_NN;
286 #endif
287 #ifdef FP_PNORM
288   case FP_PNORM: return MSVCRT__FPCLASS_PN;
289 #endif
290   }
291   return MSVCRT__FPCLASS_PN;
292 #elif defined (fpclassify)
293   switch (fpclassify( num ))
294   {
295   case FP_NAN: return MSVCRT__FPCLASS_QNAN;
296   case FP_INFINITE: return signbit(num) ? MSVCRT__FPCLASS_NINF : MSVCRT__FPCLASS_PINF;
297   case FP_SUBNORMAL: return signbit(num) ?MSVCRT__FPCLASS_ND : MSVCRT__FPCLASS_PD;
298   case FP_ZERO: return signbit(num) ? MSVCRT__FPCLASS_NZ : MSVCRT__FPCLASS_PZ;
299   }
300   return signbit(num) ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN;
301 #else
302   if (!finite(num))
303     return MSVCRT__FPCLASS_QNAN;
304   return num == 0.0 ? MSVCRT__FPCLASS_PZ : (num < 0 ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN);
305 #endif
306 }
307
308 /*********************************************************************
309  *              _rotl (MSVCRT.@)
310  */
311 unsigned int _rotl(unsigned int num, int shift)
312 {
313   shift &= 31;
314   return (num << shift) | (num >> (32-shift));
315 }
316
317 /*********************************************************************
318  *              _logb (MSVCRT.@)
319  */
320 double _logb(double num)
321 {
322   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
323   return logb(num);
324 }
325
326 /*********************************************************************
327  *              _lrotl (MSVCRT.@)
328  */
329 unsigned long _lrotl(unsigned long num, int shift)
330 {
331   shift &= 0x1f;
332   return (num << shift) | (num >> (32-shift));
333 }
334
335 /*********************************************************************
336  *              _lrotr (MSVCRT.@)
337  */
338 unsigned long _lrotr(unsigned long num, int shift)
339 {
340   shift &= 0x1f;
341   return (num >> shift) | (num << (32-shift));
342 }
343
344 /*********************************************************************
345  *              _rotr (MSVCRT.@)
346  */
347 unsigned int _rotr(unsigned int num, int shift)
348 {
349     shift &= 0x1f;
350     return (num >> shift) | (num << (32-shift));
351 }
352
353 /*********************************************************************
354  *              _scalb (MSVCRT.@)
355  */
356 double _scalb(double num, long power)
357 {
358   /* Note - Can't forward directly as libc expects y as double */
359   double dblpower = (double)power;
360   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
361   return scalb(num, dblpower);
362 }
363
364 /*********************************************************************
365  *              _matherr (MSVCRT.@)
366  */
367 int MSVCRT__matherr(struct MSVCRT__exception *e)
368 {
369   if (e)
370     TRACE("(%p = %d, %s, %g %g %g)\n",e, e->type, e->name, e->arg1, e->arg2,
371           e->retval);
372   else
373     TRACE("(null)\n");
374   if (MSVCRT_default_matherr_func)
375     return MSVCRT_default_matherr_func(e);
376   ERR(":Unhandled math error!\n");
377   return 0;
378 }
379
380 /*********************************************************************
381  *              __setusermatherr (MSVCRT.@)
382  */
383 void MSVCRT___setusermatherr(MSVCRT_matherr_func func)
384 {
385   MSVCRT_default_matherr_func = func;
386   TRACE(":new matherr handler %p\n", func);
387 }
388
389 /**********************************************************************
390  *              _statusfp (MSVCRT.@)
391  */
392 unsigned int _statusfp(void)
393 {
394    unsigned int retVal = 0;
395 #if defined(__GNUC__) && defined(__i386__)
396   unsigned int fpword;
397
398   __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
399   if (fpword & 0x1)  retVal |= MSVCRT__SW_INVALID;
400   if (fpword & 0x2)  retVal |= MSVCRT__SW_DENORMAL;
401   if (fpword & 0x4)  retVal |= MSVCRT__SW_ZERODIVIDE;
402   if (fpword & 0x8)  retVal |= MSVCRT__SW_OVERFLOW;
403   if (fpword & 0x10) retVal |= MSVCRT__SW_UNDERFLOW;
404   if (fpword & 0x20) retVal |= MSVCRT__SW_INEXACT;
405 #else
406   FIXME(":Not implemented!\n");
407 #endif
408   return retVal;
409 }
410
411 /*********************************************************************
412  *              _clearfp (MSVCRT.@)
413  */
414 unsigned int _clearfp(void)
415 {
416   unsigned int retVal = _statusfp();
417 #if defined(__GNUC__) && defined(__i386__)
418   __asm__ __volatile__( "fnclex" );
419 #else
420   FIXME(":Not Implemented\n");
421 #endif
422   return retVal;
423 }
424
425 /*********************************************************************
426  *              __fpecode (MSVCRT.@)
427  */
428 int *__fpecode(void)
429 {
430     return &msvcrt_get_thread_data()->fpecode;
431 }
432
433 /*********************************************************************
434  *              ldexp (MSVCRT.@)
435  */
436 double MSVCRT_ldexp(double num, long exp)
437 {
438   double z = ldexp(num,exp);
439
440   if (!finite(z))
441     *MSVCRT__errno() = MSVCRT_ERANGE;
442   else if (z == 0 && signbit(z))
443     z = 0.0; /* Convert -0 -> +0 */
444   return z;
445 }
446
447 /*********************************************************************
448  *              _cabs (MSVCRT.@)
449  */
450 double MSVCRT__cabs(struct MSVCRT__complex num)
451 {
452   return sqrt(num.x * num.x + num.y * num.y);
453 }
454
455 /*********************************************************************
456  *              _chgsign (MSVCRT.@)
457  */
458 double _chgsign(double num)
459 {
460   /* FIXME: +-infinity,Nan not tested */
461   return -num;
462 }
463
464 /*********************************************************************
465  *              _control87 (MSVCRT.@)
466  */
467 unsigned int _control87(unsigned int newval, unsigned int mask)
468 {
469 #if defined(__GNUC__) && defined(__i386__)
470   unsigned int fpword = 0;
471   unsigned int flags = 0;
472
473   TRACE("(%08x, %08x): Called\n", newval, mask);
474
475   /* Get fp control word */
476   __asm__ __volatile__( "fstcw %0" : "=m" (fpword) : );
477
478   TRACE("Control word before : %08x\n", fpword);
479
480   /* Convert into mask constants */
481   if (fpword & 0x1)  flags |= MSVCRT__EM_INVALID;
482   if (fpword & 0x2)  flags |= MSVCRT__EM_DENORMAL;
483   if (fpword & 0x4)  flags |= MSVCRT__EM_ZERODIVIDE;
484   if (fpword & 0x8)  flags |= MSVCRT__EM_OVERFLOW;
485   if (fpword & 0x10) flags |= MSVCRT__EM_UNDERFLOW;
486   if (fpword & 0x20) flags |= MSVCRT__EM_INEXACT;
487   switch(fpword & 0xC00) {
488   case 0xC00: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
489   case 0x800: flags |= MSVCRT__RC_UP; break;
490   case 0x400: flags |= MSVCRT__RC_DOWN; break;
491   }
492   switch(fpword & 0x300) {
493   case 0x0:   flags |= MSVCRT__PC_24; break;
494   case 0x200: flags |= MSVCRT__PC_53; break;
495   case 0x300: flags |= MSVCRT__PC_64; break;
496   }
497   if (fpword & 0x1000) flags |= MSVCRT__IC_AFFINE;
498
499   /* Mask with parameters */
500   flags = (flags & ~mask) | (newval & mask);
501
502   /* Convert (masked) value back to fp word */
503   fpword = 0;
504   if (flags & MSVCRT__EM_INVALID)    fpword |= 0x1;
505   if (flags & MSVCRT__EM_DENORMAL)   fpword |= 0x2;
506   if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x4;
507   if (flags & MSVCRT__EM_OVERFLOW)   fpword |= 0x8;
508   if (flags & MSVCRT__EM_UNDERFLOW)  fpword |= 0x10;
509   if (flags & MSVCRT__EM_INEXACT)    fpword |= 0x20;
510   switch(flags & (MSVCRT__RC_UP | MSVCRT__RC_DOWN)) {
511   case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0xC00; break;
512   case MSVCRT__RC_UP:          fpword |= 0x800; break;
513   case MSVCRT__RC_DOWN:        fpword |= 0x400; break;
514   }
515   switch (flags & (MSVCRT__PC_24 | MSVCRT__PC_53)) {
516   case MSVCRT__PC_64: fpword |= 0x300; break;
517   case MSVCRT__PC_53: fpword |= 0x200; break;
518   case MSVCRT__PC_24: fpword |= 0x0; break;
519   }
520   if (flags & MSVCRT__IC_AFFINE) fpword |= 0x1000;
521
522   TRACE("Control word after  : %08x\n", fpword);
523
524   /* Put fp control word */
525   __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
526
527   return flags;
528 #else
529   FIXME(":Not Implemented!\n");
530   return 0;
531 #endif
532 }
533
534 /*********************************************************************
535  *              _controlfp (MSVCRT.@)
536  */
537 unsigned int _controlfp(unsigned int newval, unsigned int mask)
538 {
539 #ifdef __i386__
540   return _control87( newval, mask & ~MSVCRT__EM_DENORMAL );
541 #else
542   FIXME(":Not Implemented!\n");
543   return 0;
544 #endif
545 }
546
547 /*********************************************************************
548  *              _copysign (MSVCRT.@)
549  */
550 double _copysign(double num, double sign)
551 {
552   /* FIXME: Behaviour for Nan/Inf? */
553   if (sign < 0.0)
554     return num < 0.0 ? num : -num;
555   return num < 0.0 ? -num : num;
556 }
557
558 /*********************************************************************
559  *              _finite (MSVCRT.@)
560  */
561 int  _finite(double num)
562 {
563   return (finite(num)?1:0); /* See comment for _isnan() */
564 }
565
566 /*********************************************************************
567  *              _fpreset (MSVCRT.@)
568  */
569 void _fpreset(void)
570 {
571 #if defined(__GNUC__) && defined(__i386__)
572   __asm__ __volatile__( "fninit" );
573 #else
574   FIXME(":Not Implemented!\n");
575 #endif
576 }
577
578 /*********************************************************************
579  *              _isnan (MSVCRT.@)
580  */
581 INT  _isnan(double num)
582 {
583   /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
584    * Do the same, as the result may be used in calculations
585    */
586   return isnan(num) ? 1 : 0;
587 }
588
589 /*********************************************************************
590  *              _y0 (MSVCRT.@)
591  */
592 double _y0(double num)
593 {
594   double retval;
595   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
596   retval  = y0(num);
597   if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
598   {
599     *MSVCRT__errno() = MSVCRT_EDOM;
600     retval = sqrt(-1);
601   }
602   return retval;
603 }
604
605 /*********************************************************************
606  *              _y1 (MSVCRT.@)
607  */
608 double _y1(double num)
609 {
610   double retval;
611   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
612   retval  = y1(num);
613   if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
614   {
615     *MSVCRT__errno() = MSVCRT_EDOM;
616     retval = sqrt(-1);
617   }
618   return retval;
619 }
620
621 /*********************************************************************
622  *              _yn (MSVCRT.@)
623  */
624 double _yn(int order, double num)
625 {
626   double retval;
627   if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
628   retval  = yn(order,num);
629   if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
630   {
631     *MSVCRT__errno() = MSVCRT_EDOM;
632     retval = sqrt(-1);
633   }
634   return retval;
635 }
636
637 /*********************************************************************
638  *              _nextafter (MSVCRT.@)
639  */
640 double _nextafter(double num, double next)
641 {
642   double retval;
643   if (!finite(num) || !finite(next)) *MSVCRT__errno() = MSVCRT_EDOM;
644   retval = nextafter(num,next);
645   return retval;
646 }
647
648 /*********************************************************************
649  *              _ecvt (MSVCRT.@)
650  */
651 char *_ecvt( double number, int ndigits, int *decpt, int *sign )
652 {
653     thread_data_t *data = msvcrt_get_thread_data();
654     char *dec;
655
656     if (!data->efcvt_buffer)
657         data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
658
659     snprintf(data->efcvt_buffer, 80, "%.*e", ndigits /* FIXME wrong */, number);
660     *sign = (number < 0);
661     dec = strchr(data->efcvt_buffer, '.');
662     *decpt = (dec) ? dec - data->efcvt_buffer : -1;
663     return data->efcvt_buffer;
664 }
665
666 /***********************************************************************
667  *              _fcvt  (MSVCRT.@)
668  */
669 char *_fcvt( double number, int ndigits, int *decpt, int *sign )
670 {
671     thread_data_t *data = msvcrt_get_thread_data();
672     char *dec;
673
674     if (!data->efcvt_buffer)
675         data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
676
677     snprintf(data->efcvt_buffer, 80, "%.*e", ndigits, number);
678     *sign = (number < 0);
679     dec = strchr(data->efcvt_buffer, '.');
680     *decpt = (dec) ? dec - data->efcvt_buffer : -1;
681     return data->efcvt_buffer;
682 }
683
684 /***********************************************************************
685  *              _gcvt  (MSVCRT.@)
686  *
687  * FIXME: uses both E and F.
688  */
689 char *_gcvt( double number, int ndigit, char *buff )
690 {
691     sprintf(buff, "%.*E", ndigit, number);
692     return buff;
693 }
694
695 #include <stdlib.h> /* div_t, ldiv_t */
696
697 /*********************************************************************
698  *              div (MSVCRT.@)
699  * VERSION
700  *      [i386] Windows binary compatible - returns the struct in eax/edx.
701  */
702 #ifdef __i386__
703 unsigned __int64 MSVCRT_div(int num, int denom)
704 {
705   div_t dt = div(num,denom);
706   return ((unsigned __int64)dt.rem << 32) | (unsigned int)dt.quot;
707 }
708 #else
709 /*********************************************************************
710  *              div (MSVCRT.@)
711  * VERSION
712  *      [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
713  */
714 MSVCRT_div_t MSVCRT_div(int num, int denom)
715 {
716   div_t dt = div(num,denom);
717   MSVCRT_div_t     ret;
718   ret.quot = dt.quot;
719   ret.rem = dt.rem;
720
721   return ret;
722
723 }
724 #endif /* ifdef __i386__ */
725
726
727 /*********************************************************************
728  *              ldiv (MSVCRT.@)
729  * VERSION
730  *      [i386] Windows binary compatible - returns the struct in eax/edx.
731  */
732 #ifdef __i386__
733 unsigned __int64 MSVCRT_ldiv(long num, long denom)
734 {
735   ldiv_t ldt = ldiv(num,denom);
736   return ((unsigned __int64)ldt.rem << 32) | (unsigned long)ldt.quot;
737 }
738 #else
739 /*********************************************************************
740  *              ldiv (MSVCRT.@)
741  * VERSION
742  *      [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
743  */
744 MSVCRT_ldiv_t MSVCRT_ldiv(long num, long denom)
745 {
746   ldiv_t result = ldiv(num,denom);
747
748   MSVCRT_ldiv_t ret;
749   ret.quot = result.quot;
750   ret.rem = result.rem;
751
752   return ret;
753 }
754 #endif /* ifdef __i386__ */
755
756 /***********************************************************************
757  *              _adj_fdiv_m16i (MSVCRT.@)
758  *
759  * NOTE
760  *    I _think_ this function is intended to work around the Pentium
761  *    fdiv bug.
762  */
763 void __stdcall _adj_fdiv_m16i( short arg )
764 {
765   TRACE("(): stub\n");
766 }
767
768 /***********************************************************************
769  *              _adj_fdiv_m32 (MSVCRT.@)
770  *
771  * NOTE
772  *    I _think_ this function is intended to work around the Pentium
773  *    fdiv bug.
774  */
775 void __stdcall _adj_fdiv_m32( unsigned int arg )
776 {
777   TRACE("(): stub\n");
778 }
779
780 /***********************************************************************
781  *              _adj_fdiv_m32i (MSVCRT.@)
782  *
783  * NOTE
784  *    I _think_ this function is intended to work around the Pentium
785  *    fdiv bug.
786  */
787 void __stdcall _adj_fdiv_m32i( int arg )
788 {
789   TRACE("(): stub\n");
790 }
791
792 /***********************************************************************
793  *              _adj_fdiv_m64 (MSVCRT.@)
794  *
795  * NOTE
796  *    I _think_ this function is intended to work around the Pentium
797  *    fdiv bug.
798  */
799 void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
800 {
801   TRACE("(): stub\n");
802 }
803
804 /***********************************************************************
805  *              _adj_fdiv_r (MSVCRT.@)
806  * FIXME
807  *    This function is likely to have the wrong number of arguments.
808  *
809  * NOTE
810  *    I _think_ this function is intended to work around the Pentium
811  *    fdiv bug.
812  */
813 void _adj_fdiv_r(void)
814 {
815   TRACE("(): stub\n");
816 }
817
818 /***********************************************************************
819  *              _adj_fdivr_m16i (MSVCRT.@)
820  *
821  * NOTE
822  *    I _think_ this function is intended to work around the Pentium
823  *    fdiv bug.
824  */
825 void __stdcall _adj_fdivr_m16i( short arg )
826 {
827   TRACE("(): stub\n");
828 }
829
830 /***********************************************************************
831  *              _adj_fdivr_m32 (MSVCRT.@)
832  *
833  * NOTE
834  *    I _think_ this function is intended to work around the Pentium
835  *    fdiv bug.
836  */
837 void __stdcall _adj_fdivr_m32( unsigned int arg )
838 {
839   TRACE("(): stub\n");
840 }
841
842 /***********************************************************************
843  *              _adj_fdivr_m32i (MSVCRT.@)
844  *
845  * NOTE
846  *    I _think_ this function is intended to work around the Pentium
847  *    fdiv bug.
848  */
849 void __stdcall _adj_fdivr_m32i( int arg )
850 {
851   TRACE("(): stub\n");
852 }
853
854 /***********************************************************************
855  *              _adj_fdivr_m64 (MSVCRT.@)
856  *
857  * NOTE
858  *    I _think_ this function is intended to work around the Pentium
859  *    fdiv bug.
860  */
861 void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
862 {
863   TRACE("(): stub\n");
864 }
865
866 /***********************************************************************
867  *              _adj_fpatan (MSVCRT.@)
868  * FIXME
869  *    This function is likely to have the wrong number of arguments.
870  *
871  * NOTE
872  *    I _think_ this function is intended to work around the Pentium
873  *    fdiv bug.
874  */
875 void _adj_fpatan(void)
876 {
877   TRACE("(): stub\n");
878 }
879
880 /***********************************************************************
881  *              _adj_fprem (MSVCRT.@)
882  * FIXME
883  *    This function is likely to have the wrong number of arguments.
884  *
885  * NOTE
886  *    I _think_ this function is intended to work around the Pentium
887  *    fdiv bug.
888  */
889 void _adj_fprem(void)
890 {
891   TRACE("(): stub\n");
892 }
893
894 /***********************************************************************
895  *              _adj_fprem1 (MSVCRT.@)
896  * FIXME
897  *    This function is likely to have the wrong number of arguments.
898  *
899  * NOTE
900  *    I _think_ this function is intended to work around the Pentium
901  *    fdiv bug.
902  */
903 void _adj_fprem1(void)
904 {
905   TRACE("(): stub\n");
906 }
907
908 /***********************************************************************
909  *              _adj_fptan (MSVCRT.@)
910  * FIXME
911  *    This function is likely to have the wrong number of arguments.
912  *
913  * NOTE
914  *    I _think_ this function is intended to work around the Pentium
915  *    fdiv bug.
916  */
917 void _adj_fptan(void)
918 {
919   TRACE("(): stub\n");
920 }
921
922 /***********************************************************************
923  *              _adjust_fdiv (MSVCRT.@)
924  * FIXME
925  *    I _think_ this function should be a variable indicating whether
926  *    Pentium fdiv bug safe code should be used.
927  */
928 void _adjust_fdiv(void)
929 {
930   TRACE("(): stub\n");
931 }
932
933 /***********************************************************************
934  *              _safe_fdiv (MSVCRT.@)
935  * FIXME
936  *    This function is likely to have the wrong number of arguments.
937  *
938  * NOTE
939  *    I _think_ this function is intended to work around the Pentium
940  *    fdiv bug.
941  */
942 void _safe_fdiv(void)
943 {
944   TRACE("(): stub\n");
945 }
946
947 /***********************************************************************
948  *              _safe_fdivr (MSVCRT.@)
949  * FIXME
950  *    This function is likely to have the wrong number of arguments.
951  *
952  * NOTE
953  *    I _think_ this function is intended to work around the Pentium
954  *    fdiv bug.
955  */
956 void _safe_fdivr(void)
957 {
958   TRACE("(): stub\n");
959 }
960
961 /***********************************************************************
962  *              _safe_fprem (MSVCRT.@)
963  * FIXME
964  *    This function is likely to have the wrong number of arguments.
965  *
966  * NOTE
967  *    I _think_ this function is intended to work around the Pentium
968  *    fdiv bug.
969  */
970 void _safe_fprem(void)
971 {
972   TRACE("(): stub\n");
973 }
974
975 /***********************************************************************
976  *              _safe_fprem1 (MSVCRT.@)
977  *
978  * FIXME
979  *    This function is likely to have the wrong number of arguments.
980  *
981  * NOTE
982  *    I _think_ this function is intended to work around the Pentium
983  *    fdiv bug.
984  */
985 void _safe_fprem1(void)
986 {
987   TRACE("(): stub\n");
988 }