1 
2 /* @(#)e_fmod.c 5.1 93/09/24 */
3 /*
4  * ====================================================
5  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6  *
7  * Developed at SunPro, a Sun Microsystems, Inc. business.
8  * Permission to use, copy, modify, and distribute this
9  * software is freely granted, provided that this notice
10  * is preserved.
11  * ====================================================
12  */
13 
14 /*
15  * fmod(x,y)
16  * Return x mod y in exact arithmetic
17  * Method: shift and subtract
18  */
19 
20 #include "fdlibm.h"
21 
22 #ifdef _NEED_FLOAT64
23 
24 static const __float64
25     one = _F_64(1.0),
26     Zero[] = { _F_64(0.0), _F_64(-0.0) };
27 
28 __float64
fmod64(__float64 x,__float64 y)29 fmod64(__float64 x, __float64 y)
30 {
31     __int32_t n, hx, hy, hz, ix, iy, sx, i;
32     __uint32_t lx, ly, lz;
33 
34     EXTRACT_WORDS(hx, lx, x);
35     EXTRACT_WORDS(hy, ly, y);
36     sx = hx & 0x80000000; /* sign of x */
37     hx ^= sx; /* |x| */
38     hy &= 0x7fffffff; /* |y| */
39 
40     /* purge off exception values */
41     if (isnan(x) || isnan(y)) /* x or y nan, return nan */
42         return x + y;
43 
44     if (isinf(x)) /* x == inf, domain error */
45         return __math_invalid(x);
46 
47     if ((hy | ly) == 0) /* y=0, domain error */
48         return __math_invalid(y);
49 
50     if (hx <= hy) {
51         if ((hx < hy) || (lx < ly))
52             return x; /* |x|<|y| return x */
53         if (lx == ly)
54             return Zero[(__uint32_t)sx >> 31]; /* |x|=|y| return x*0*/
55     }
56 
57     /* determine ix = ilogb(x) */
58     if (hx < 0x00100000) { /* subnormal x */
59         if (hx == 0) {
60             for (ix = -1043, i = lx; i > 0; i <<= 1)
61                 ix -= 1;
62         } else {
63             for (ix = -1022, i = (hx << 11); i > 0; i <<= 1)
64                 ix -= 1;
65         }
66     } else
67         ix = (hx >> 20) - 1023;
68 
69     /* determine iy = ilogb(y) */
70     if (hy < 0x00100000) { /* subnormal y */
71         if (hy == 0) {
72             for (iy = -1043, i = ly; i > 0; i <<= 1)
73                 iy -= 1;
74         } else {
75             for (iy = -1022, i = (hy << 11); i > 0; i <<= 1)
76                 iy -= 1;
77         }
78     } else
79         iy = (hy >> 20) - 1023;
80 
81     /* set up {hx,lx}, {hy,ly} and align y to x */
82     if (ix >= -1022)
83         hx = 0x00100000 | (0x000fffff & hx);
84     else { /* subnormal x, shift x to normal */
85         n = -1022 - ix;
86         if (n <= 31) {
87             hx = (hx << n) | (lx >> (32 - n));
88             lx <<= n;
89         } else {
90             hx = lx << (n - 32);
91             lx = 0;
92         }
93     }
94     if (iy >= -1022)
95         hy = 0x00100000 | (0x000fffff & hy);
96     else { /* subnormal y, shift y to normal */
97         n = -1022 - iy;
98         if (n <= 31) {
99             hy = (hy << n) | (ly >> (32 - n));
100             ly <<= n;
101         } else {
102             hy = ly << (n - 32);
103             ly = 0;
104         }
105     }
106 
107     /* fix point fmod */
108     n = ix - iy;
109     while (n--) {
110         hz = hx - hy;
111         lz = lx - ly;
112         if (lx < ly)
113             hz -= 1;
114         if (hz < 0) {
115             hx = hx + hx + (lx >> 31);
116             lx = lx + lx;
117         } else {
118             if ((hz | lz) == 0) /* return sign(x)*0 */
119                 return Zero[(__uint32_t)sx >> 31];
120             hx = hz + hz + (lz >> 31);
121             lx = lz + lz;
122         }
123     }
124     hz = hx - hy;
125     lz = lx - ly;
126     if (lx < ly)
127         hz -= 1;
128     if (hz >= 0) {
129         hx = hz;
130         lx = lz;
131     }
132 
133     /* convert back to floating value and restore the sign */
134     if ((hx | lx) == 0) /* return sign(x)*0 */
135         return Zero[(__uint32_t)sx >> 31];
136     while (hx < 0x00100000) { /* normalize x */
137         hx = hx + hx + (lx >> 31);
138         lx = lx + lx;
139         iy -= 1;
140     }
141     if (iy >= -1022) { /* normalize output */
142         hx = ((hx - 0x00100000) | ((iy + 1023) << 20));
143         INSERT_WORDS(x, hx | sx, lx);
144     } else { /* subnormal output */
145         n = -1022 - iy;
146         if (n <= 20) {
147             lx = (lx >> n) | ((__uint32_t)hx << (32 - n));
148             hx >>= n;
149         } else if (n <= 31) {
150             lx = (hx << (32 - n)) | (lx >> n);
151             hx = sx;
152         } else {
153             lx = hx >> (n - 32);
154             hx = sx;
155         }
156         INSERT_WORDS(x, hx | sx, lx);
157         x *= one; /* create necessary signal */
158     }
159     return x; /* exact output */
160 }
161 
162 _MATH_ALIAS_d_dd(fmod)
163 
164 #endif /* _NEED_FLOAT64 */
165