1 /* e_fmodl.c -- long double version of e_fmod.c.
2 */
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 * __ieee754_fmodl(x,y)
16 * Return x mod y in exact arithmetic
17 * Method: shift and subtract
18 */
19
20 #include <math.h>
21 #include <math_private.h>
22 #include <ieee754.h>
23 #include <libm-alias-finite.h>
24
25 static const long double one = 1.0, Zero[] = {0.0, -0.0,};
26
27 long double
__ieee754_fmodl(long double x,long double y)28 __ieee754_fmodl (long double x, long double y)
29 {
30 int64_t hx, hy, hz, sx, sy;
31 uint64_t lx, ly, lz;
32 int n, ix, iy;
33 double xhi, xlo, yhi, ylo;
34
35 ldbl_unpack (x, &xhi, &xlo);
36 EXTRACT_WORDS64 (hx, xhi);
37 EXTRACT_WORDS64 (lx, xlo);
38 ldbl_unpack (y, &yhi, &ylo);
39 EXTRACT_WORDS64 (hy, yhi);
40 EXTRACT_WORDS64 (ly, ylo);
41 sx = hx&0x8000000000000000ULL; /* sign of x */
42 hx ^= sx; /* |x| */
43 sy = hy&0x8000000000000000ULL; /* sign of y */
44 hy ^= sy; /* |y| */
45
46 /* purge off exception values */
47 if(__builtin_expect(hy==0 ||
48 (hx>=0x7ff0000000000000LL)|| /* y=0,or x not finite */
49 (hy>0x7ff0000000000000LL),0)) /* or y is NaN */
50 return (x*y)/(x*y);
51 if (__glibc_unlikely (hx <= hy))
52 {
53 /* If |x| < |y| return x. */
54 if (hx < hy)
55 return x;
56 /* At this point the absolute value of the high doubles of
57 x and y must be equal. */
58 if ((lx & 0x7fffffffffffffffLL) == 0
59 && (ly & 0x7fffffffffffffffLL) == 0)
60 /* Both low parts are zero. The result should be an
61 appropriately signed zero, but the subsequent logic
62 could treat them as unequal, depending on the signs
63 of the low parts. */
64 return Zero[(uint64_t) sx >> 63];
65 /* If the low double of y is the same sign as the high
66 double of y (ie. the low double increases |y|)... */
67 if (((ly ^ sy) & 0x8000000000000000LL) == 0
68 /* ... then a different sign low double to high double
69 for x or same sign but lower magnitude... */
70 && (int64_t) (lx ^ sx) < (int64_t) (ly ^ sy))
71 /* ... means |x| < |y|. */
72 return x;
73 /* If the low double of x differs in sign to the high
74 double of x (ie. the low double decreases |x|)... */
75 if (((lx ^ sx) & 0x8000000000000000LL) != 0
76 /* ... then a different sign low double to high double
77 for y with lower magnitude (we've already caught
78 the same sign for y case above)... */
79 && (int64_t) (lx ^ sx) > (int64_t) (ly ^ sy))
80 /* ... means |x| < |y|. */
81 return x;
82 /* If |x| == |y| return x*0. */
83 if ((lx ^ sx) == (ly ^ sy))
84 return Zero[(uint64_t) sx >> 63];
85 }
86
87 /* Make the IBM extended format 105 bit mantissa look like the ieee854 112
88 bit mantissa so the following operations will give the correct
89 result. */
90 ldbl_extract_mantissa(&hx, &lx, &ix, x);
91 ldbl_extract_mantissa(&hy, &ly, &iy, y);
92
93 if (__glibc_unlikely (ix == -IEEE754_DOUBLE_BIAS))
94 {
95 /* subnormal x, shift x to normal. */
96 while ((hx & (1LL << 48)) == 0)
97 {
98 hx = (hx << 1) | (lx >> 63);
99 lx = lx << 1;
100 ix -= 1;
101 }
102 }
103
104 if (__glibc_unlikely (iy == -IEEE754_DOUBLE_BIAS))
105 {
106 /* subnormal y, shift y to normal. */
107 while ((hy & (1LL << 48)) == 0)
108 {
109 hy = (hy << 1) | (ly >> 63);
110 ly = ly << 1;
111 iy -= 1;
112 }
113 }
114
115 /* fix point fmod */
116 n = ix - iy;
117 while(n--) {
118 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
119 if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
120 else {
121 if((hz|lz)==0) /* return sign(x)*0 */
122 return Zero[(uint64_t)sx>>63];
123 hx = hz+hz+(lz>>63); lx = lz+lz;
124 }
125 }
126 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
127 if(hz>=0) {hx=hz;lx=lz;}
128
129 /* convert back to floating value and restore the sign */
130 if((hx|lx)==0) /* return sign(x)*0 */
131 return Zero[(uint64_t)sx>>63];
132 while(hx<0x0001000000000000LL) { /* normalize x */
133 hx = hx+hx+(lx>>63); lx = lx+lx;
134 iy -= 1;
135 }
136 if(__builtin_expect(iy>= -1022,0)) { /* normalize output */
137 x = ldbl_insert_mantissa((sx>>63), iy, hx, lx);
138 } else { /* subnormal output */
139 n = -1022 - iy;
140 /* We know 1 <= N <= 52, and that there are no nonzero
141 bits in places below 2^-1074. */
142 lx = (lx >> n) | ((uint64_t) hx << (64 - n));
143 hx >>= n;
144 x = ldbl_insert_mantissa((sx>>63), -1023, hx, lx);
145 x *= one; /* create necessary signal */
146 }
147 return x; /* exact output */
148 }
149 libm_alias_finite (__ieee754_fmodl, __fmodl)
150