1 /* @(#)e_fmod.c 5.1 93/09/24 */
2 /*
3 * ====================================================
4 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5 *
6 * Developed at SunPro, a Sun Microsystems, Inc. business.
7 * Permission to use, copy, modify, and distribute this
8 * software is freely granted, provided that this notice
9 * is preserved.
10 * ====================================================
11 */
12
13 /*
14 * fmodl(x,y)
15 * Return x mod y in exact arithmetic
16 * Method: shift and subtract
17 */
18
19
20
21 static const long double one = 1.0L, Zero[] = {0.0L, -0.0L,};
22
23 long double
fmodl(long double x,long double y)24 fmodl(long double x, long double y)
25 {
26 int64_t n,hx,hy,hz,ix,iy,sx,i;
27 u_int64_t lx,ly,lz;
28
29 GET_LDOUBLE_WORDS64(hx,lx,x);
30 GET_LDOUBLE_WORDS64(hy,ly,y);
31 sx = hx&0x8000000000000000ULL; /* sign of x */
32 hx ^=sx; /* |x| */
33 hy &= 0x7fffffffffffffffLL; /* |y| */
34
35 if (isnanl(x) || isnanl(y))
36 return x + y;
37
38 if (isinfl(x))
39 return __math_invalidl(x);
40
41 if (y == 0.0L)
42 return __math_invalidl(y);
43
44 if(hx<=hy) {
45 if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
46 if(lx==ly)
47 return Zero[(u_int64_t)sx>>63]; /* |x|=|y| return x*0*/
48 }
49
50 /* determine ix = ilogb(x) */
51 if(hx<0x0001000000000000LL) { /* subnormal x */
52 if(hx==0) {
53 for (ix = -16431, i=lx; i>0; i<<=1) ix -=1;
54 } else {
55 for (ix = -16382, i=hx<<15; i>0; i<<=1) ix -=1;
56 }
57 } else ix = (hx>>48)-0x3fff;
58
59 /* determine iy = ilogb(y) */
60 if(hy<0x0001000000000000LL) { /* subnormal y */
61 if(hy==0) {
62 for (iy = -16431, i=ly; i>0; i<<=1) iy -=1;
63 } else {
64 for (iy = -16382, i=hy<<15; i>0; i<<=1) iy -=1;
65 }
66 } else iy = (hy>>48)-0x3fff;
67
68 /* set up {hx,lx}, {hy,ly} and align y to x */
69 if(ix >= -16382)
70 hx = 0x0001000000000000LL|(0x0000ffffffffffffLL&hx);
71 else { /* subnormal x, shift x to normal */
72 n = -16382-ix;
73 if(n<=63) {
74 hx = (hx<<n)|(lx>>(64-n));
75 lx <<= n;
76 } else {
77 hx = lx<<(n-64);
78 lx = 0;
79 }
80 }
81 if(iy >= -16382)
82 hy = 0x0001000000000000LL|(0x0000ffffffffffffLL&hy);
83 else { /* subnormal y, shift y to normal */
84 n = -16382-iy;
85 if(n<=63) {
86 hy = (hy<<n)|(ly>>(64-n));
87 ly <<= n;
88 } else {
89 hy = ly<<(n-64);
90 ly = 0;
91 }
92 }
93
94 /* fix point fmod */
95 n = ix - iy;
96 while(n--) {
97 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
98 if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
99 else {
100 if((hz|lz)==0) /* return sign(x)*0 */
101 return Zero[(u_int64_t)sx>>63];
102 hx = hz+hz+(lz>>63); lx = lz+lz;
103 }
104 }
105 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
106 if(hz>=0) {hx=hz;lx=lz;}
107
108 /* convert back to floating value and restore the sign */
109 if((hx|lx)==0) /* return sign(x)*0 */
110 return Zero[(u_int64_t)sx>>63];
111 while(hx<0x0001000000000000LL) { /* normalize x */
112 hx = hx+hx+(lx>>63); lx = lx+lx;
113 iy -= 1;
114 }
115 if(iy>= -16382) { /* normalize output */
116 hx = ((hx-0x0001000000000000LL)|((iy+16383)<<48));
117 SET_LDOUBLE_WORDS64(x,hx|sx,lx);
118 } else { /* subnormal output */
119 n = -16382 - iy;
120 if(n<=48) {
121 lx = (lx>>n)|((u_int64_t)hx<<(64-n));
122 hx >>= n;
123 } else if (n<=63) {
124 lx = (hx<<(64-n))|(lx>>n); hx = sx;
125 } else {
126 lx = hx>>(n-64); hx = sx;
127 }
128 SET_LDOUBLE_WORDS64(x,hx|sx,lx);
129 x *= one; /* create necessary signal */
130 }
131 return x; /* exact output */
132 }
133