math.c 30.7 KB
Newer Older
1 2 3 4
/*
 * msvcrt.dll math functions
 *
 * Copyright 2000 Jon Griffiths
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 24 25 26 27 28 29
#define __USE_ISOC9X 1
#define __USE_ISOC99 1
#include <math.h>
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif

30
#include "msvcrt.h"
31

32 33 34
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

#ifndef HAVE_FINITE
#ifndef finite /* Could be a macro */
#ifdef isfinite
#define finite(x) isfinite(x)
#else
#define finite(x) (!isnan(x)) /* At least catch some cases */
#endif
#endif
#endif

#ifndef signbit
#define signbit(x) 0
#endif

50
typedef int (*MSVCRT_matherr_func)(struct MSVCRT__exception *);
51 52 53

static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;

54 55 56
/*********************************************************************
 *		MSVCRT_acos (MSVCRT.@)
 */
57
double CDECL MSVCRT_acos( double x )
58 59
{
  if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
60 61 62 63 64 65
  /* glibc implements acos() as the FPU equivalent of atan2(sqrt(1 - x ^ 2), x).
   * asin() uses a similar construction. This is bad because as x gets nearer to
   * 1 the error in the expression "1 - x^2" can get relatively large due to
   * cancellation. The sqrt() makes things worse. A safer way to calculate
   * acos() is to use atan2(sqrt((1 - x) * (1 + x)), x). */
  return atan2(sqrt((1 - x) * (1 + x)), x);
66 67 68 69 70
}

/*********************************************************************
 *		MSVCRT_asin (MSVCRT.@)
 */
71
double CDECL MSVCRT_asin( double x )
72 73
{
  if (x < -1.0 || x > 1.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
74
  return atan2(x, sqrt((1 - x) * (1 + x)));
75 76 77 78 79
}

/*********************************************************************
 *		MSVCRT_atan (MSVCRT.@)
 */
80
double CDECL MSVCRT_atan( double x )
81 82 83 84 85 86 87 88
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return atan(x);
}

/*********************************************************************
 *		MSVCRT_atan2 (MSVCRT.@)
 */
89
double CDECL MSVCRT_atan2( double x, double y )
90 91 92 93 94 95 96 97
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return atan2(x,y);
}

/*********************************************************************
 *		MSVCRT_cos (MSVCRT.@)
 */
98
double CDECL MSVCRT_cos( double x )
99 100 101 102 103 104 105 106
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return cos(x);
}

/*********************************************************************
 *		MSVCRT_cosh (MSVCRT.@)
 */
107
double CDECL MSVCRT_cosh( double x )
108 109 110 111 112 113 114 115
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return cosh(x);
}

/*********************************************************************
 *		MSVCRT_exp (MSVCRT.@)
 */
116
double CDECL MSVCRT_exp( double x )
117 118 119 120 121 122 123 124
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return exp(x);
}

/*********************************************************************
 *		MSVCRT_fmod (MSVCRT.@)
 */
125
double CDECL MSVCRT_fmod( double x, double y )
126 127 128 129 130 131 132 133
{
  if (!finite(x) || !finite(y)) *MSVCRT__errno() = MSVCRT_EDOM;
  return fmod(x,y);
}

/*********************************************************************
 *		MSVCRT_log (MSVCRT.@)
 */
134
double CDECL MSVCRT_log( double x)
135 136 137 138 139 140 141 142 143
{
  if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
  return log(x);
}

/*********************************************************************
 *		MSVCRT_log10 (MSVCRT.@)
 */
144
double CDECL MSVCRT_log10( double x )
145 146 147 148 149 150 151 152 153
{
  if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  if (x == 0.0) *MSVCRT__errno() = MSVCRT_ERANGE;
  return log10(x);
}

/*********************************************************************
 *		MSVCRT_pow (MSVCRT.@)
 */
154
double CDECL MSVCRT_pow( double x, double y )
155 156 157 158 159 160 161 162 163 164
{
  /* FIXME: If x < 0 and y is not integral, set EDOM */
  double z = pow(x,y);
  if (!finite(z)) *MSVCRT__errno() = MSVCRT_EDOM;
  return z;
}

/*********************************************************************
 *		MSVCRT_sin (MSVCRT.@)
 */
165
double CDECL MSVCRT_sin( double x )
166 167 168 169 170 171 172 173
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return sin(x);
}

/*********************************************************************
 *		MSVCRT_sinh (MSVCRT.@)
 */
174
double CDECL MSVCRT_sinh( double x )
175 176 177 178 179 180 181 182
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return sinh(x);
}

/*********************************************************************
 *		MSVCRT_sqrt (MSVCRT.@)
 */
183
double CDECL MSVCRT_sqrt( double x )
184 185 186 187 188 189 190 191
{
  if (x < 0.0 || !finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return sqrt(x);
}

/*********************************************************************
 *		MSVCRT_tan (MSVCRT.@)
 */
192
double CDECL MSVCRT_tan( double x )
193 194 195 196 197 198 199 200
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return tan(x);
}

/*********************************************************************
 *		MSVCRT_tanh (MSVCRT.@)
 */
201
double CDECL MSVCRT_tanh( double x )
202 203 204 205 206 207
{
  if (!finite(x)) *MSVCRT__errno() = MSVCRT_EDOM;
  return tanh(x);
}


208 209 210 211 212 213 214 215 216 217 218
#if defined(__GNUC__) && defined(__i386__)

#define FPU_DOUBLE(var) double var; \
  __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
#define FPU_DOUBLES(var1,var2) double var1,var2; \
  __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
  __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )

/*********************************************************************
 *		_CIacos (MSVCRT.@)
 */
219
double CDECL _CIacos(void)
220 221
{
  FPU_DOUBLE(x);
222
  return MSVCRT_acos(x);
223 224 225 226 227
}

/*********************************************************************
 *		_CIasin (MSVCRT.@)
 */
228
double CDECL _CIasin(void)
229 230
{
  FPU_DOUBLE(x);
231
  return MSVCRT_asin(x);
232 233 234 235 236
}

/*********************************************************************
 *		_CIatan (MSVCRT.@)
 */
237
double CDECL _CIatan(void)
238 239
{
  FPU_DOUBLE(x);
240
  return MSVCRT_atan(x);
241 242 243 244 245
}

/*********************************************************************
 *		_CIatan2 (MSVCRT.@)
 */
246
double CDECL _CIatan2(void)
247 248
{
  FPU_DOUBLES(x,y);
249
  return MSVCRT_atan2(x,y);
250 251 252 253 254
}

/*********************************************************************
 *		_CIcos (MSVCRT.@)
 */
255
double CDECL _CIcos(void)
256 257
{
  FPU_DOUBLE(x);
258
  return MSVCRT_cos(x);
259 260 261 262 263
}

/*********************************************************************
 *		_CIcosh (MSVCRT.@)
 */
264
double CDECL _CIcosh(void)
265 266
{
  FPU_DOUBLE(x);
267
  return MSVCRT_cosh(x);
268 269 270 271 272
}

/*********************************************************************
 *		_CIexp (MSVCRT.@)
 */
273
double CDECL _CIexp(void)
274 275
{
  FPU_DOUBLE(x);
276
  return MSVCRT_exp(x);
277 278 279 280 281
}

/*********************************************************************
 *		_CIfmod (MSVCRT.@)
 */
282
double CDECL _CIfmod(void)
283 284
{
  FPU_DOUBLES(x,y);
285
  return MSVCRT_fmod(x,y);
286 287 288 289 290
}

/*********************************************************************
 *		_CIlog (MSVCRT.@)
 */
291
double CDECL _CIlog(void)
292 293
{
  FPU_DOUBLE(x);
294
  return MSVCRT_log(x);
295 296 297 298 299
}

/*********************************************************************
 *		_CIlog10 (MSVCRT.@)
 */
300
double CDECL _CIlog10(void)
301 302
{
  FPU_DOUBLE(x);
303
  return MSVCRT_log10(x);
304 305 306 307 308
}

/*********************************************************************
 *		_CIpow (MSVCRT.@)
 */
309
double CDECL _CIpow(void)
310 311
{
  FPU_DOUBLES(x,y);
312
  return MSVCRT_pow(x,y);
313 314 315 316 317
}

/*********************************************************************
 *		_CIsin (MSVCRT.@)
 */
318
double CDECL _CIsin(void)
319 320
{
  FPU_DOUBLE(x);
321
  return MSVCRT_sin(x);
322 323 324 325 326
}

/*********************************************************************
 *		_CIsinh (MSVCRT.@)
 */
327
double CDECL _CIsinh(void)
328 329
{
  FPU_DOUBLE(x);
330
  return MSVCRT_sinh(x);
331 332 333 334 335
}

/*********************************************************************
 *		_CIsqrt (MSVCRT.@)
 */
336
double CDECL _CIsqrt(void)
337 338
{
  FPU_DOUBLE(x);
339
  return MSVCRT_sqrt(x);
340 341 342 343 344
}

/*********************************************************************
 *		_CItan (MSVCRT.@)
 */
345
double CDECL _CItan(void)
346 347
{
  FPU_DOUBLE(x);
348
  return MSVCRT_tan(x);
349 350 351 352 353
}

/*********************************************************************
 *		_CItanh (MSVCRT.@)
 */
354
double CDECL _CItanh(void)
355 356
{
  FPU_DOUBLE(x);
357
  return MSVCRT_tanh(x);
358 359 360 361 362 363 364
}

#endif /* defined(__GNUC__) && defined(__i386__) */

/*********************************************************************
 *		_fpclass (MSVCRT.@)
 */
365
int CDECL _fpclass(double num)
366 367 368 369
{
#if defined(HAVE_FPCLASS) || defined(fpclass)
  switch (fpclass( num ))
  {
Alexandre Julliard's avatar
Alexandre Julliard committed
370
#ifdef FP_SNAN
371
  case FP_SNAN:  return MSVCRT__FPCLASS_SNAN;
Alexandre Julliard's avatar
Alexandre Julliard committed
372 373
#endif
#ifdef FP_QNAN
374
  case FP_QNAN:  return MSVCRT__FPCLASS_QNAN;
Alexandre Julliard's avatar
Alexandre Julliard committed
375 376
#endif
#ifdef FP_NINF
377
  case FP_NINF:  return MSVCRT__FPCLASS_NINF;
Alexandre Julliard's avatar
Alexandre Julliard committed
378 379
#endif
#ifdef FP_PINF
380
  case FP_PINF:  return MSVCRT__FPCLASS_PINF;
Alexandre Julliard's avatar
Alexandre Julliard committed
381 382
#endif
#ifdef FP_NDENORM
383
  case FP_NDENORM: return MSVCRT__FPCLASS_ND;
Alexandre Julliard's avatar
Alexandre Julliard committed
384 385
#endif
#ifdef FP_PDENORM
386
  case FP_PDENORM: return MSVCRT__FPCLASS_PD;
Alexandre Julliard's avatar
Alexandre Julliard committed
387 388
#endif
#ifdef FP_NZERO
389
  case FP_NZERO: return MSVCRT__FPCLASS_NZ;
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391
#endif
#ifdef FP_PZERO
392
  case FP_PZERO: return MSVCRT__FPCLASS_PZ;
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394
#endif
#ifdef FP_NNORM
395
  case FP_NNORM: return MSVCRT__FPCLASS_NN;
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397
#endif
#ifdef FP_PNORM
398
  case FP_PNORM: return MSVCRT__FPCLASS_PN;
Alexandre Julliard's avatar
Alexandre Julliard committed
399
#endif
400
  default: return MSVCRT__FPCLASS_PN;
401 402 403 404
  }
#elif defined (fpclassify)
  switch (fpclassify( num ))
  {
405 406 407 408
  case FP_NAN: return MSVCRT__FPCLASS_QNAN;
  case FP_INFINITE: return signbit(num) ? MSVCRT__FPCLASS_NINF : MSVCRT__FPCLASS_PINF;
  case FP_SUBNORMAL: return signbit(num) ?MSVCRT__FPCLASS_ND : MSVCRT__FPCLASS_PD;
  case FP_ZERO: return signbit(num) ? MSVCRT__FPCLASS_NZ : MSVCRT__FPCLASS_PZ;
409
  }
410
  return signbit(num) ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN;
411 412
#else
  if (!finite(num))
413 414
    return MSVCRT__FPCLASS_QNAN;
  return num == 0.0 ? MSVCRT__FPCLASS_PZ : (num < 0 ? MSVCRT__FPCLASS_NN : MSVCRT__FPCLASS_PN);
415 416 417 418 419 420
#endif
}

/*********************************************************************
 *		_rotl (MSVCRT.@)
 */
421
unsigned int CDECL _rotl(unsigned int num, int shift)
422 423 424 425 426 427 428 429
{
  shift &= 31;
  return (num << shift) | (num >> (32-shift));
}

/*********************************************************************
 *		_logb (MSVCRT.@)
 */
430
double CDECL _logb(double num)
431
{
432
  if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
433 434 435 436 437 438
  return logb(num);
}

/*********************************************************************
 *		_lrotl (MSVCRT.@)
 */
439
MSVCRT_ulong CDECL _lrotl(MSVCRT_ulong num, int shift)
440 441 442 443 444 445 446 447
{
  shift &= 0x1f;
  return (num << shift) | (num >> (32-shift));
}

/*********************************************************************
 *		_lrotr (MSVCRT.@)
 */
448
MSVCRT_ulong CDECL _lrotr(MSVCRT_ulong num, int shift)
449 450 451 452 453 454 455 456
{
  shift &= 0x1f;
  return (num >> shift) | (num << (32-shift));
}

/*********************************************************************
 *		_rotr (MSVCRT.@)
 */
457
unsigned int CDECL _rotr(unsigned int num, int shift)
458 459 460 461 462 463 464 465
{
    shift &= 0x1f;
    return (num >> shift) | (num << (32-shift));
}

/*********************************************************************
 *		_scalb (MSVCRT.@)
 */
466
double CDECL _scalb(double num, MSVCRT_long power)
467 468 469
{
  /* Note - Can't forward directly as libc expects y as double */
  double dblpower = (double)power;
470
  if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
471 472 473
  return scalb(num, dblpower);
}

474 475 476
/*********************************************************************
 *		_hypot (MSVCRT.@)
 */
477
double CDECL _hypot(double x, double y)
478 479 480 481 482 483 484 485
{
  /* FIXME: errno handling */
  return hypot( x, y );
}

/*********************************************************************
 *		ceil (MSVCRT.@)
 */
486
double CDECL MSVCRT_ceil( double x )
487 488 489 490 491 492 493
{
  return ceil(x);
}

/*********************************************************************
 *		floor (MSVCRT.@)
 */
494
double CDECL MSVCRT_floor( double x )
495 496 497 498 499 500 501
{
  return floor(x);
}

/*********************************************************************
 *		fabs (MSVCRT.@)
 */
502
double CDECL MSVCRT_fabs( double x )
503 504 505 506 507 508 509
{
  return fabs(x);
}

/*********************************************************************
 *		frexp (MSVCRT.@)
 */
510
double CDECL MSVCRT_frexp( double x, int *exp )
511 512 513 514 515 516 517
{
  return frexp( x, exp );
}

/*********************************************************************
 *		modf (MSVCRT.@)
 */
518
double CDECL MSVCRT_modf( double x, double *iptr )
519 520 521 522
{
  return modf( x, iptr );
}

523 524 525
/*********************************************************************
 *		_matherr (MSVCRT.@)
 */
526
int CDECL MSVCRT__matherr(struct MSVCRT__exception *e)
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
{
  if (e)
    TRACE("(%p = %d, %s, %g %g %g)\n",e, e->type, e->name, e->arg1, e->arg2,
          e->retval);
  else
    TRACE("(null)\n");
  if (MSVCRT_default_matherr_func)
    return MSVCRT_default_matherr_func(e);
  ERR(":Unhandled math error!\n");
  return 0;
}

/*********************************************************************
 *		__setusermatherr (MSVCRT.@)
 */
542
void CDECL MSVCRT___setusermatherr(MSVCRT_matherr_func func)
543 544 545 546 547 548 549 550
{
  MSVCRT_default_matherr_func = func;
  TRACE(":new matherr handler %p\n", func);
}

/**********************************************************************
 *		_statusfp (MSVCRT.@)
 */
551
unsigned int CDECL _statusfp(void)
552 553 554 555 556 557
{
   unsigned int retVal = 0;
#if defined(__GNUC__) && defined(__i386__)
  unsigned int fpword;

  __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
558 559 560 561 562 563
  if (fpword & 0x1)  retVal |= MSVCRT__SW_INVALID;
  if (fpword & 0x2)  retVal |= MSVCRT__SW_DENORMAL;
  if (fpword & 0x4)  retVal |= MSVCRT__SW_ZERODIVIDE;
  if (fpword & 0x8)  retVal |= MSVCRT__SW_OVERFLOW;
  if (fpword & 0x10) retVal |= MSVCRT__SW_UNDERFLOW;
  if (fpword & 0x20) retVal |= MSVCRT__SW_INEXACT;
564 565 566 567 568 569 570 571 572
#else
  FIXME(":Not implemented!\n");
#endif
  return retVal;
}

/*********************************************************************
 *		_clearfp (MSVCRT.@)
 */
573
unsigned int CDECL _clearfp(void)
574
{
575
  unsigned int retVal = _statusfp();
576 577 578 579 580 581 582 583
#if defined(__GNUC__) && defined(__i386__)
  __asm__ __volatile__( "fnclex" );
#else
  FIXME(":Not Implemented\n");
#endif
  return retVal;
}

584 585 586
/*********************************************************************
 *		__fpecode (MSVCRT.@)
 */
587
int * CDECL __fpecode(void)
588 589 590 591
{
    return &msvcrt_get_thread_data()->fpecode;
}

592 593 594
/*********************************************************************
 *		ldexp (MSVCRT.@)
 */
595
double CDECL MSVCRT_ldexp(double num, MSVCRT_long exp)
596 597 598 599
{
  double z = ldexp(num,exp);

  if (!finite(z))
600
    *MSVCRT__errno() = MSVCRT_ERANGE;
601 602 603 604 605 606 607 608
  else if (z == 0 && signbit(z))
    z = 0.0; /* Convert -0 -> +0 */
  return z;
}

/*********************************************************************
 *		_cabs (MSVCRT.@)
 */
609
double CDECL MSVCRT__cabs(struct MSVCRT__complex num)
610
{
611
  return sqrt(num.x * num.x + num.y * num.y);
612 613 614 615 616
}

/*********************************************************************
 *		_chgsign (MSVCRT.@)
 */
617
double CDECL _chgsign(double num)
618 619 620 621 622 623 624 625
{
  /* FIXME: +-infinity,Nan not tested */
  return -num;
}

/*********************************************************************
 *		_control87 (MSVCRT.@)
 */
626
unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
627 628
{
#if defined(__GNUC__) && defined(__i386__)
629 630 631 632
  unsigned int fpword = 0;
  unsigned int flags = 0;

  TRACE("(%08x, %08x): Called\n", newval, mask);
633 634

  /* Get fp control word */
635 636 637
  __asm__ __volatile__( "fstcw %0" : "=m" (fpword) : );

  TRACE("Control word before : %08x\n", fpword);
638 639

  /* Convert into mask constants */
640 641 642 643 644 645
  if (fpword & 0x1)  flags |= MSVCRT__EM_INVALID;
  if (fpword & 0x2)  flags |= MSVCRT__EM_DENORMAL;
  if (fpword & 0x4)  flags |= MSVCRT__EM_ZERODIVIDE;
  if (fpword & 0x8)  flags |= MSVCRT__EM_OVERFLOW;
  if (fpword & 0x10) flags |= MSVCRT__EM_UNDERFLOW;
  if (fpword & 0x20) flags |= MSVCRT__EM_INEXACT;
646
  switch(fpword & 0xC00) {
647 648 649
  case 0xC00: flags |= MSVCRT__RC_UP|MSVCRT__RC_DOWN; break;
  case 0x800: flags |= MSVCRT__RC_UP; break;
  case 0x400: flags |= MSVCRT__RC_DOWN; break;
650 651
  }
  switch(fpword & 0x300) {
652 653 654
  case 0x0:   flags |= MSVCRT__PC_24; break;
  case 0x200: flags |= MSVCRT__PC_53; break;
  case 0x300: flags |= MSVCRT__PC_64; break;
655
  }
656
  if (fpword & 0x1000) flags |= MSVCRT__IC_AFFINE;
657 658 659 660 661 662

  /* Mask with parameters */
  flags = (flags & ~mask) | (newval & mask);

  /* Convert (masked) value back to fp word */
  fpword = 0;
663 664 665 666 667 668 669 670 671 672
  if (flags & MSVCRT__EM_INVALID)    fpword |= 0x1;
  if (flags & MSVCRT__EM_DENORMAL)   fpword |= 0x2;
  if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x4;
  if (flags & MSVCRT__EM_OVERFLOW)   fpword |= 0x8;
  if (flags & MSVCRT__EM_UNDERFLOW)  fpword |= 0x10;
  if (flags & MSVCRT__EM_INEXACT)    fpword |= 0x20;
  switch(flags & (MSVCRT__RC_UP | MSVCRT__RC_DOWN)) {
  case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0xC00; break;
  case MSVCRT__RC_UP:          fpword |= 0x800; break;
  case MSVCRT__RC_DOWN:        fpword |= 0x400; break;
673
  }
674 675 676 677
  switch (flags & (MSVCRT__PC_24 | MSVCRT__PC_53)) {
  case MSVCRT__PC_64: fpword |= 0x300; break;
  case MSVCRT__PC_53: fpword |= 0x200; break;
  case MSVCRT__PC_24: fpword |= 0x0; break;
678
  }
679
  if (flags & MSVCRT__IC_AFFINE) fpword |= 0x1000;
680 681

  TRACE("Control word after  : %08x\n", fpword);
682 683 684

  /* Put fp control word */
  __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
685 686

  return flags;
687
#else
688 689
  FIXME(":Not Implemented!\n");
  return 0;
690 691 692 693 694 695
#endif
}

/*********************************************************************
 *		_controlfp (MSVCRT.@)
 */
696
unsigned int CDECL _controlfp(unsigned int newval, unsigned int mask)
697
{
698
#ifdef __i386__
699
  return _control87( newval, mask & ~MSVCRT__EM_DENORMAL );
700 701 702 703
#else
  FIXME(":Not Implemented!\n");
  return 0;
#endif
704 705 706 707 708
}

/*********************************************************************
 *		_copysign (MSVCRT.@)
 */
709
double CDECL _copysign(double num, double sign)
710 711 712 713 714 715 716 717 718 719
{
  /* FIXME: Behaviour for Nan/Inf? */
  if (sign < 0.0)
    return num < 0.0 ? num : -num;
  return num < 0.0 ? -num : num;
}

/*********************************************************************
 *		_finite (MSVCRT.@)
 */
720
int CDECL _finite(double num)
721 722 723 724 725 726 727
{
  return (finite(num)?1:0); /* See comment for _isnan() */
}

/*********************************************************************
 *		_fpreset (MSVCRT.@)
 */
728
void CDECL _fpreset(void)
729 730 731 732 733 734 735 736 737 738 739
{
#if defined(__GNUC__) && defined(__i386__)
  __asm__ __volatile__( "fninit" );
#else
  FIXME(":Not Implemented!\n");
#endif
}

/*********************************************************************
 *		_isnan (MSVCRT.@)
 */
740
INT CDECL _isnan(double num)
741 742 743 744 745 746 747
{
  /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1.
   * Do the same, as the result may be used in calculations
   */
  return isnan(num) ? 1 : 0;
}

748 749 750
/*********************************************************************
 *		_j0 (MSVCRT.@)
 */
751
double CDECL _j0(double num)
752 753 754 755 756 757 758 759
{
  /* FIXME: errno handling */
  return j0(num);
}

/*********************************************************************
 *		_j1 (MSVCRT.@)
 */
760
double CDECL _j1(double num)
761 762 763 764 765 766 767 768
{
  /* FIXME: errno handling */
  return j1(num);
}

/*********************************************************************
 *		jn (MSVCRT.@)
 */
769
double CDECL _jn(int n, double num)
770 771 772 773 774
{
  /* FIXME: errno handling */
  return jn(n, num);
}

775 776 777
/*********************************************************************
 *		_y0 (MSVCRT.@)
 */
778
double CDECL _y0(double num)
779 780
{
  double retval;
781
  if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
782
  retval  = y0(num);
783
  if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
784
  {
785
    *MSVCRT__errno() = MSVCRT_EDOM;
786 787 788 789 790 791 792 793
    retval = sqrt(-1);
  }
  return retval;
}

/*********************************************************************
 *		_y1 (MSVCRT.@)
 */
794
double CDECL _y1(double num)
795 796
{
  double retval;
797
  if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
798
  retval  = y1(num);
799
  if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
800
  {
801
    *MSVCRT__errno() = MSVCRT_EDOM;
802 803 804 805 806 807 808 809
    retval = sqrt(-1);
  }
  return retval;
}

/*********************************************************************
 *		_yn (MSVCRT.@)
 */
810
double CDECL _yn(int order, double num)
811 812
{
  double retval;
813
  if (!finite(num)) *MSVCRT__errno() = MSVCRT_EDOM;
814
  retval  = yn(order,num);
815
  if (_fpclass(retval) == MSVCRT__FPCLASS_NINF)
816
  {
817
    *MSVCRT__errno() = MSVCRT_EDOM;
818 819 820 821 822 823 824 825
    retval = sqrt(-1);
  }
  return retval;
}

/*********************************************************************
 *		_nextafter (MSVCRT.@)
 */
826
double CDECL _nextafter(double num, double next)
827 828
{
  double retval;
829
  if (!finite(num) || !finite(next)) *MSVCRT__errno() = MSVCRT_EDOM;
830 831 832 833
  retval = nextafter(num,next);
  return retval;
}

834 835 836
/*********************************************************************
 *		_ecvt (MSVCRT.@)
 */
837
char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
838
{
839
    int prec, len;
840
    thread_data_t *data = msvcrt_get_thread_data();
841 842 843 844
    /* FIXME: check better for overflow (native supports over 300 chars's) */
    ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
                                      * 4 for exponent and one for
                                      * terminating '\0' */
845 846 847
    if (!data->efcvt_buffer)
        data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */

848 849 850 851 852 853 854 855
    if( number < 0) {
        *sign = TRUE;
        number = -number;
    } else
        *sign = FALSE;
    /* handle cases with zero ndigits or less */
    prec = ndigits;
    if( prec < 1) prec = 2;
856
    len = snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
857 858
    /* take the decimal "point away */
    if( prec != 1)
859
        memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
    /* take the exponential "e" out */
    data->efcvt_buffer[ prec] = '\0';
    /* read the exponent */
    sscanf( data->efcvt_buffer + prec + 1, "%d", decpt);
    (*decpt)++;
    /* adjust for some border cases */
    if( data->efcvt_buffer[0] == '0')/* value is zero */
        *decpt = 0;
    /* handle cases with zero ndigits or less */
    if( ndigits < 1){
        if( data->efcvt_buffer[ 0] >= '5')
            (*decpt)++;
        data->efcvt_buffer[ 0] = '\0';
    }
    TRACE("out=\"%s\"\n",data->efcvt_buffer);
875 876 877 878 879 880
    return data->efcvt_buffer;
}

/***********************************************************************
 *		_fcvt  (MSVCRT.@)
 */
881
char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
882
{
883
    thread_data_t *data = msvcrt_get_thread_data();
884 885 886
    int stop, dec1, dec2;
    char *ptr1, *ptr2, *first;
    char buf[80]; /* ought to be enough */
887 888 889 890

    if (!data->efcvt_buffer)
        data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
    if (number < 0)
    {
	*sign = 1;
	number = -number;
    } else *sign = 0;

    snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
    ptr1 = buf;
    ptr2 = data->efcvt_buffer;
    first = NULL;
    dec1 = 0;
    dec2 = 0;

    /* For numbers below the requested resolution, work out where
       the decimal point will be rather than finding it in the string */
    if (number < 1.0 && number > 0.0) {
	dec2 = log10(number + 1e-10);
	if (-dec2 <= ndigits) dec2 = 0;
    }

    /* If requested digits is zero or less, we will need to truncate
     * the returned string */
    if (ndigits < 1) {
	stop = strlen(buf) + ndigits;
    } else {
	stop = strlen(buf);
    }

    while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
    while (*ptr1 != '\0' && *ptr1 != '.') {
	if (!first) first = ptr2;
	if ((ptr1 - buf) < stop) {
	    *ptr2++ = *ptr1++;
	} else {
	    ptr1++;
	}
	dec1++;
    }

    if (ndigits > 0) {
	ptr1++;
	if (!first) {
	    while (*ptr1 == '0') { /* Process leading zeroes */
		*ptr2++ = *ptr1++;
		dec1--;
	    }
	}
	while (*ptr1 != '\0') {
	    if (!first) first = ptr2;
	    *ptr2++ = *ptr1++;
	}
    }

    *ptr2 = '\0';

    /* We never found a non-zero digit, then our number is either
     * smaller than the requested precision, or 0.0 */
    if (!first) {
	if (number > 0.0) {
	    first = ptr2;
	} else {
	    first = data->efcvt_buffer;
	    dec1 = 0;
	}
    }

    *decpt = dec2 ? dec2 : dec1;
    return first;
959 960 961 962 963 964 965
}

/***********************************************************************
 *		_gcvt  (MSVCRT.@)
 *
 * FIXME: uses both E and F.
 */
966
char * CDECL _gcvt( double number, int ndigit, char *buff )
967 968 969 970 971
{
    sprintf(buff, "%.*E", ndigit, number);
    return buff;
}

972 973 974 975 976 977 978 979
#include <stdlib.h> /* div_t, ldiv_t */

/*********************************************************************
 *		div (MSVCRT.@)
 * VERSION
 *	[i386] Windows binary compatible - returns the struct in eax/edx.
 */
#ifdef __i386__
980
unsigned __int64 CDECL MSVCRT_div(int num, int denom)
981 982
{
  div_t dt = div(num,denom);
983
  return ((unsigned __int64)dt.rem << 32) | (unsigned int)dt.quot;
984 985 986 987 988 989 990
}
#else
/*********************************************************************
 *		div (MSVCRT.@)
 * VERSION
 *	[!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
 */
991
MSVCRT_div_t CDECL MSVCRT_div(int num, int denom)
992
{
993 994 995 996 997 998 999
  div_t dt = div(num,denom);
  MSVCRT_div_t     ret;
  ret.quot = dt.quot;
  ret.rem = dt.rem;

  return ret;

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
}
#endif /* ifdef __i386__ */


/*********************************************************************
 *		ldiv (MSVCRT.@)
 * VERSION
 * 	[i386] Windows binary compatible - returns the struct in eax/edx.
 */
#ifdef __i386__
1010
unsigned __int64 CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1011 1012
{
  ldiv_t ldt = ldiv(num,denom);
1013
  return ((unsigned __int64)ldt.rem << 32) | (MSVCRT_ulong)ldt.quot;
1014 1015 1016 1017 1018 1019 1020
}
#else
/*********************************************************************
 *		ldiv (MSVCRT.@)
 * VERSION
 *	[!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
 */
1021
MSVCRT_ldiv_t CDECL MSVCRT_ldiv(MSVCRT_long num, MSVCRT_long denom)
1022
{
1023 1024 1025 1026 1027 1028 1029
  ldiv_t result = ldiv(num,denom);

  MSVCRT_ldiv_t ret;
  ret.quot = result.quot;
  ret.rem = result.rem;

  return ret;
1030 1031 1032
}
#endif /* ifdef __i386__ */

1033 1034 1035 1036 1037 1038 1039 1040
#ifdef __i386__

/*********************************************************************
 *		_adjust_fdiv (MSVCRT.@)
 * Used by the MSVC compiler to work around the Pentium FDIV bug.
 */
int MSVCRT__adjust_fdiv = 0;

1041 1042 1043 1044 1045 1046 1047
/***********************************************************************
 *		_adj_fdiv_m16i (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1048
void __stdcall _adj_fdiv_m16i( short arg )
1049
{
1050
  TRACE("(): stub\n");
1051 1052 1053 1054 1055 1056 1057 1058 1059
}

/***********************************************************************
 *		_adj_fdiv_m32 (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1060
void __stdcall _adj_fdiv_m32( unsigned int arg )
1061
{
1062
  TRACE("(): stub\n");
1063 1064 1065 1066 1067 1068 1069 1070 1071
}

/***********************************************************************
 *		_adj_fdiv_m32i (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1072
void __stdcall _adj_fdiv_m32i( int arg )
1073
{
1074
  TRACE("(): stub\n");
1075 1076 1077 1078 1079 1080 1081 1082 1083
}

/***********************************************************************
 *		_adj_fdiv_m64 (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1084
void __stdcall _adj_fdiv_m64( unsigned __int64 arg )
1085
{
1086
  TRACE("(): stub\n");
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
}

/***********************************************************************
 *		_adj_fdiv_r (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1098
void _adj_fdiv_r(void)
1099
{
1100
  TRACE("(): stub\n");
1101 1102 1103 1104 1105 1106 1107 1108 1109
}

/***********************************************************************
 *		_adj_fdivr_m16i (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1110
void __stdcall _adj_fdivr_m16i( short arg )
1111
{
1112
  TRACE("(): stub\n");
1113 1114 1115 1116 1117 1118 1119 1120 1121
}

/***********************************************************************
 *		_adj_fdivr_m32 (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1122
void __stdcall _adj_fdivr_m32( unsigned int arg )
1123
{
1124
  TRACE("(): stub\n");
1125 1126 1127 1128 1129 1130 1131 1132 1133
}

/***********************************************************************
 *		_adj_fdivr_m32i (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1134
void __stdcall _adj_fdivr_m32i( int arg )
1135
{
1136
  TRACE("(): stub\n");
1137 1138 1139 1140 1141 1142 1143 1144 1145
}

/***********************************************************************
 *		_adj_fdivr_m64 (MSVCRT.@)
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1146
void __stdcall _adj_fdivr_m64( unsigned __int64 arg )
1147
{
1148
  TRACE("(): stub\n");
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
}

/***********************************************************************
 *		_adj_fpatan (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1160
void _adj_fpatan(void)
1161
{
1162
  TRACE("(): stub\n");
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
}

/***********************************************************************
 *		_adj_fprem (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1174
void _adj_fprem(void)
1175
{
1176
  TRACE("(): stub\n");
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
}

/***********************************************************************
 *		_adj_fprem1 (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1188
void _adj_fprem1(void)
1189
{
1190
  TRACE("(): stub\n");
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
}

/***********************************************************************
 *		_adj_fptan (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1202
void _adj_fptan(void)
1203
{
1204
  TRACE("(): stub\n");
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
}

/***********************************************************************
 *		_safe_fdiv (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1216
void _safe_fdiv(void)
1217
{
1218
  TRACE("(): stub\n");
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
}

/***********************************************************************
 *		_safe_fdivr (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1230
void _safe_fdivr(void)
1231
{
1232
  TRACE("(): stub\n");
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
}

/***********************************************************************
 *		_safe_fprem (MSVCRT.@)
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1244
void _safe_fprem(void)
1245
{
1246
  TRACE("(): stub\n");
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
}

/***********************************************************************
 *		_safe_fprem1 (MSVCRT.@)
 *
 * FIXME
 *    This function is likely to have the wrong number of arguments.
 *
 * NOTE
 *    I _think_ this function is intended to work around the Pentium
 *    fdiv bug.
 */
1259
void _safe_fprem1(void)
1260
{
1261
  TRACE("(): stub\n");
1262
}
1263 1264

#endif  /* __i386__ */