fmod.c 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #include <math.h>
  2. #include <stdint.h>
  3. double fmod(double x, double y)
  4. {
  5. union {double f; uint64_t i;} ux = {x}, uy = {y};
  6. int ex = ux.i>>52 & 0x7ff;
  7. int ey = uy.i>>52 & 0x7ff;
  8. int sx = ux.i>>63;
  9. uint64_t i;
  10. /* in the followings uxi should be ux.i, but then gcc wrongly adds */
  11. /* float load/store to inner loops ruining performance and code size */
  12. uint64_t uxi = ux.i;
  13. if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
  14. return (x*y)/(x*y);
  15. if (uxi<<1 <= uy.i<<1) {
  16. if (uxi<<1 == uy.i<<1)
  17. return 0*x;
  18. return x;
  19. }
  20. /* normalize x and y */
  21. if (!ex) {
  22. for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
  23. uxi <<= -ex + 1;
  24. } else {
  25. uxi &= -1ULL >> 12;
  26. uxi |= 1ULL << 52;
  27. }
  28. if (!ey) {
  29. for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
  30. uy.i <<= -ey + 1;
  31. } else {
  32. uy.i &= -1ULL >> 12;
  33. uy.i |= 1ULL << 52;
  34. }
  35. /* x mod y */
  36. for (; ex > ey; ex--) {
  37. i = uxi - uy.i;
  38. if (i >> 63 == 0) {
  39. if (i == 0)
  40. return 0*x;
  41. uxi = i;
  42. }
  43. uxi <<= 1;
  44. }
  45. i = uxi - uy.i;
  46. if (i >> 63 == 0) {
  47. if (i == 0)
  48. return 0*x;
  49. uxi = i;
  50. }
  51. for (; uxi>>52 == 0; uxi <<= 1, ex--);
  52. /* scale result */
  53. if (ex > 0) {
  54. uxi -= 1ULL << 52;
  55. uxi |= (uint64_t)ex << 52;
  56. } else {
  57. uxi >>= -ex + 1;
  58. }
  59. uxi |= (uint64_t)sx << 63;
  60. ux.i = uxi;
  61. return ux.f;
  62. }