1
0

fmodf.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /* origin: FreeBSD /usr/src/lib/msun/src/e_fmodf.c */
  2. /*
  3. * Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected].
  4. */
  5. /*
  6. * ====================================================
  7. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  8. *
  9. * Developed at SunPro, a Sun Microsystems, Inc. business.
  10. * Permission to use, copy, modify, and distribute this
  11. * software is freely granted, provided that this notice
  12. * is preserved.
  13. * ====================================================
  14. */
  15. /*
  16. * fmodf(x,y)
  17. * Return x mod y in exact arithmetic
  18. * Method: shift and subtract
  19. */
  20. #include "libm.h"
  21. static const float Zero[] = {0.0, -0.0,};
  22. float fmodf(float x, float y)
  23. {
  24. int32_t n,hx,hy,hz,ix,iy,sx,i;
  25. GET_FLOAT_WORD(hx, x);
  26. GET_FLOAT_WORD(hy, y);
  27. sx = hx & 0x80000000; /* sign of x */
  28. hx ^= sx; /* |x| */
  29. hy &= 0x7fffffff; /* |y| */
  30. /* purge off exception values */
  31. if (hy == 0 || hx >= 0x7f800000 || /* y=0,or x not finite */
  32. hy > 0x7f800000) /* or y is NaN */
  33. return (x*y)/(x*y);
  34. if (hx < hy) /* |x| < |y| */
  35. return x;
  36. if (hx == hy) /* |x| = |y|, return x*0 */
  37. return Zero[(uint32_t)sx>>31];
  38. /* determine ix = ilogb(x) */
  39. if (hx < 0x00800000) { /* subnormal x */
  40. for (ix = -126, i = hx<<8; i > 0; i <<= 1)
  41. ix -= 1;
  42. } else
  43. ix = (hx>>23) - 127;
  44. /* determine iy = ilogb(y) */
  45. if (hy < 0x00800000) { /* subnormal y */
  46. for (iy = -126, i = hy<<8; i >= 0; i <<= 1)
  47. iy -= 1;
  48. } else
  49. iy = (hy>>23) - 127;
  50. /* set up {hx,lx}, {hy,ly} and align y to x */
  51. if (ix >= -126)
  52. hx = 0x00800000|(0x007fffff&hx);
  53. else { /* subnormal x, shift x to normal */
  54. n = -126-ix;
  55. hx = hx<<n;
  56. }
  57. if (iy >= -126)
  58. hy = 0x00800000|(0x007fffff&hy);
  59. else { /* subnormal y, shift y to normal */
  60. n = -126-iy;
  61. hy = hy<<n;
  62. }
  63. /* fix point fmod */
  64. n = ix - iy;
  65. while (n--) {
  66. hz = hx-hy;
  67. if (hz<0)
  68. hx = hx+hx;
  69. else {
  70. if(hz == 0) /* return sign(x)*0 */
  71. return Zero[(uint32_t)sx>>31];
  72. hx = hz+hz;
  73. }
  74. }
  75. hz = hx-hy;
  76. if (hz >= 0)
  77. hx = hz;
  78. /* convert back to floating value and restore the sign */
  79. if (hx == 0) /* return sign(x)*0 */
  80. return Zero[(uint32_t)sx>>31];
  81. while (hx < 0x00800000) { /* normalize x */
  82. hx = hx+hx;
  83. iy -= 1;
  84. }
  85. if (iy >= -126) { /* normalize output */
  86. hx = ((hx-0x00800000)|((iy+127)<<23));
  87. SET_FLOAT_WORD(x, hx|sx);
  88. } else { /* subnormal output */
  89. n = -126 - iy;
  90. hx >>= n;
  91. SET_FLOAT_WORD(x, hx|sx);
  92. }
  93. return x; /* exact output */
  94. }