596170bbe641b483478d0d6f8978a9e43301d2ea
[libm] / src / math / remquol.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_remquol.c */
2 /*-
3  * ====================================================
4  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5  *
6  * Developed at SunSoft, 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 #include "libm.h"
14 #if LD64
15 long double remquol(long double x, long double y, int *quo)
16 {
17         return remquo(x, y, quo);
18 }
19 #elif LD80 || LD128
20
21 #define BIAS (LDBL_MAX_EXP - 1)
22
23 #if LDBL_MANL_SIZE > 32
24 typedef uint64_t manl_t;
25 #else
26 typedef uint32_t manl_t;
27 #endif
28
29 #if LDBL_MANH_SIZE > 32
30 typedef uint64_t manh_t;
31 #else
32 typedef uint32_t manh_t;
33 #endif
34
35 /*
36  * These macros add and remove an explicit integer bit in front of the
37  * fractional mantissa, if the architecture doesn't have such a bit by
38  * default already.
39  */
40 #ifdef LDBL_IMPLICIT_NBIT
41 #define SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
42 #define HFRAC_BITS      LDBL_MANH_SIZE
43 #else
44 #define SET_NBIT(hx)    (hx)
45 #define HFRAC_BITS      (LDBL_MANH_SIZE - 1)
46 #endif
47
48 #define MANL_SHIFT      (LDBL_MANL_SIZE - 1)
49
50 static const long double Zero[] = {0.0L, -0.0L};
51
52 /*
53  * Return the IEEE remainder and set *quo to the last n bits of the
54  * quotient, rounded to the nearest integer.  We choose n=31 because
55  * we wind up computing all the integer bits of the quotient anyway as
56  * a side-effect of computing the remainder by the shift and subtract
57  * method.  In practice, this is far more bits than are needed to use
58  * remquo in reduction algorithms.
59  *
60  * Assumptions:
61  * - The low part of the mantissa fits in a manl_t exactly.
62  * - The high part of the mantissa fits in an int64_t with enough room
63  *   for an explicit integer bit in front of the fractional bits.
64  */
65 long double remquol(long double x, long double y, int *quo)
66 {
67         union IEEEl2bits ux, uy;
68         int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
69         manh_t hy;
70         manl_t lx,ly,lz;
71         int ix,iy,n,q,sx,sxy;
72
73         ux.e = x;
74         uy.e = y;
75         sx = ux.bits.sign;
76         sxy = sx ^ uy.bits.sign;
77         ux.bits.sign = 0;       /* |x| */
78         uy.bits.sign = 0;       /* |y| */
79         x = ux.e;
80
81         /* purge off exception values */
82         if ((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */
83             (ux.bits.exp == BIAS + LDBL_MAX_EXP) ||       /* or x not finite */
84             (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
85                 ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */
86                 return (x*y)/(x*y);
87         if (ux.bits.exp <= uy.bits.exp) {
88                 if ((ux.bits.exp < uy.bits.exp) ||
89                     (ux.bits.manh <= uy.bits.manh &&
90                      (ux.bits.manh < uy.bits.manh ||
91                       ux.bits.manl < uy.bits.manl))) {
92                         q = 0;
93                         goto fixup;       /* |x|<|y| return x or x-y */
94                 }
95                 if (ux.bits.manh == uy.bits.manh && ux.bits.manl == uy.bits.manl) {
96                         *quo = 1;
97                         return Zero[sx];  /* |x|=|y| return x*0*/
98                 }
99         }
100
101         /* determine ix = ilogb(x) */
102         if (ux.bits.exp == 0) {  /* subnormal x */
103                 ux.e *= 0x1.0p512;
104                 ix = ux.bits.exp - (BIAS + 512);
105         } else {
106                 ix = ux.bits.exp - BIAS;
107         }
108
109         /* determine iy = ilogb(y) */
110         if (uy.bits.exp == 0) {  /* subnormal y */
111                 uy.e *= 0x1.0p512;
112                 iy = uy.bits.exp - (BIAS + 512);
113         } else {
114                 iy = uy.bits.exp - BIAS;
115         }
116
117         /* set up {hx,lx}, {hy,ly} and align y to x */
118         hx = SET_NBIT(ux.bits.manh);
119         hy = SET_NBIT(uy.bits.manh);
120         lx = ux.bits.manl;
121         ly = uy.bits.manl;
122
123         /* fix point fmod */
124         n = ix - iy;
125         q = 0;
126
127         while (n--) {
128                 hz = hx - hy;
129                 lz = lx - ly;
130                 if (lx < ly)
131                         hz -= 1;
132                 if (hz < 0) {
133                         hx = hx + hx + (lx>>MANL_SHIFT);
134                         lx = lx + lx;
135                 } else {
136                         hx = hz + hz + (lz>>MANL_SHIFT);
137                         lx = lz + lz;
138                         q++;
139                 }
140                 q <<= 1;
141         }
142         hz = hx - hy;
143         lz = lx - ly;
144         if (lx < ly)
145                 hz -= 1;
146         if (hz >= 0) {
147                 hx = hz;
148                 lx = lz;
149                 q++;
150         }
151
152         /* convert back to floating value and restore the sign */
153         if ((hx|lx) == 0) {  /* return sign(x)*0 */
154                 *quo = sxy ? -q : q;
155                 return Zero[sx];
156         }
157         while (hx < (1ULL<<HFRAC_BITS)) {  /* normalize x */
158                 hx = hx + hx + (lx>>MANL_SHIFT);
159                 lx = lx + lx;
160                 iy -= 1;
161         }
162         ux.bits.manh = hx; /* The integer bit is truncated here if needed. */
163         ux.bits.manl = lx;
164         if (iy < LDBL_MIN_EXP) {
165                 ux.bits.exp = iy + (BIAS + 512);
166                 ux.e *= 0x1p-512;
167         } else {
168                 ux.bits.exp = iy + BIAS;
169         }
170         ux.bits.sign = 0;
171         x = ux.e;
172 fixup:
173         y = fabsl(y);
174         if (y < LDBL_MIN * 2) {
175                 if (x + x > y || (x + x == y && (q & 1))) {
176                         q++;
177                         x-=y;
178                 }
179         } else if (x > 0.5*y || (x == 0.5*y && (q & 1))) {
180                 q++;
181                 x-=y;
182         }
183
184         ux.e = x;
185         ux.bits.sign ^= sx;
186         x = ux.e;
187
188         q &= 0x7fffffff;
189         *quo = sxy ? -q : q;
190         return x;
191 }
192 #endif