xref: /illumos-gate/usr/src/lib/libc/sparc/fp/_Q_div.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "quad.h"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate static const double C[] = {
32*7c478bd9Sstevel@tonic-gate 	0.0,
33*7c478bd9Sstevel@tonic-gate 	1.0,
34*7c478bd9Sstevel@tonic-gate 	68719476736.0,
35*7c478bd9Sstevel@tonic-gate 	402653184.0,
36*7c478bd9Sstevel@tonic-gate 	24.0,
37*7c478bd9Sstevel@tonic-gate 	16.0,
38*7c478bd9Sstevel@tonic-gate 	3.66210937500000000000e-04,
39*7c478bd9Sstevel@tonic-gate 	1.52587890625000000000e-05,
40*7c478bd9Sstevel@tonic-gate 	1.43051147460937500000e-06,
41*7c478bd9Sstevel@tonic-gate 	5.96046447753906250000e-08,
42*7c478bd9Sstevel@tonic-gate 	3.72529029846191406250e-09,
43*7c478bd9Sstevel@tonic-gate 	2.18278728425502777100e-11,
44*7c478bd9Sstevel@tonic-gate 	8.52651282912120223045e-14,
45*7c478bd9Sstevel@tonic-gate 	3.55271367880050092936e-15,
46*7c478bd9Sstevel@tonic-gate 	1.30104260698260532081e-18,
47*7c478bd9Sstevel@tonic-gate 	8.67361737988403547206e-19,
48*7c478bd9Sstevel@tonic-gate 	2.16840434497100886801e-19,
49*7c478bd9Sstevel@tonic-gate 	3.17637355220362627151e-22,
50*7c478bd9Sstevel@tonic-gate 	7.75481824268463445192e-26,
51*7c478bd9Sstevel@tonic-gate 	4.62223186652936604733e-33,
52*7c478bd9Sstevel@tonic-gate 	9.62964972193617926528e-35,
53*7c478bd9Sstevel@tonic-gate 	4.70197740328915003187e-38,
54*7c478bd9Sstevel@tonic-gate 	2.75506488473973634680e-40,
55*7c478bd9Sstevel@tonic-gate };
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #define	zero		C[0]
58*7c478bd9Sstevel@tonic-gate #define	one		C[1]
59*7c478bd9Sstevel@tonic-gate #define	two36		C[2]
60*7c478bd9Sstevel@tonic-gate #define	three2p27	C[3]
61*7c478bd9Sstevel@tonic-gate #define	three2p3	C[4]
62*7c478bd9Sstevel@tonic-gate #define	two4		C[5]
63*7c478bd9Sstevel@tonic-gate #define	three2m13	C[6]
64*7c478bd9Sstevel@tonic-gate #define	twom16		C[7]
65*7c478bd9Sstevel@tonic-gate #define	three2m21	C[8]
66*7c478bd9Sstevel@tonic-gate #define	twom24		C[9]
67*7c478bd9Sstevel@tonic-gate #define	twom28		C[10]
68*7c478bd9Sstevel@tonic-gate #define	three2m37	C[11]
69*7c478bd9Sstevel@tonic-gate #define	three2m45	C[12]
70*7c478bd9Sstevel@tonic-gate #define	twom48		C[13]
71*7c478bd9Sstevel@tonic-gate #define	three2m61	C[14]
72*7c478bd9Sstevel@tonic-gate #define	twom60		C[15]
73*7c478bd9Sstevel@tonic-gate #define	twom62		C[16]
74*7c478bd9Sstevel@tonic-gate #define	three2m73	C[17]
75*7c478bd9Sstevel@tonic-gate #define	three2m85	C[18]
76*7c478bd9Sstevel@tonic-gate #define	three2m109	C[19]
77*7c478bd9Sstevel@tonic-gate #define	twom113		C[20]
78*7c478bd9Sstevel@tonic-gate #define	twom124		C[21]
79*7c478bd9Sstevel@tonic-gate #define	three2m133	C[22]
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static const unsigned int
82*7c478bd9Sstevel@tonic-gate 	fsr_re = 0x00000000u,
83*7c478bd9Sstevel@tonic-gate 	fsr_rn = 0xc0000000u;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * _Qp_div(pz, x, y) sets *pz = *x / *y.
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate void
91*7c478bd9Sstevel@tonic-gate _Qp_div(union longdouble *pz, const union longdouble *x,
92*7c478bd9Sstevel@tonic-gate 	const union longdouble *y)
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate #else
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate  * _Q_div(x, y) returns *x / *y.
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate union longdouble
100*7c478bd9Sstevel@tonic-gate _Q_div(const union longdouble *x, const union longdouble *y)
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate 	union longdouble	z;
106*7c478bd9Sstevel@tonic-gate 	union xdouble		u;
107*7c478bd9Sstevel@tonic-gate 	double			c, d, ry, xx[4], yy[5], zz[5];
108*7c478bd9Sstevel@tonic-gate 	unsigned int		xm, ym, fsr, lx, ly, wx[3], wy[3];
109*7c478bd9Sstevel@tonic-gate 	unsigned int		msw, frac2, frac3, frac4, rm;
110*7c478bd9Sstevel@tonic-gate 	int			ibit, ex, ey, ez, sign;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	xm = x->l.msw & 0x7fffffff;
113*7c478bd9Sstevel@tonic-gate 	ym = y->l.msw & 0x7fffffff;
114*7c478bd9Sstevel@tonic-gate 	sign = (x->l.msw ^ y->l.msw) & ~0x7fffffff;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	__quad_getfsrp(&fsr);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	/* handle nan and inf cases */
119*7c478bd9Sstevel@tonic-gate 	if (xm >= 0x7fff0000 || ym >= 0x7fff0000) {
120*7c478bd9Sstevel@tonic-gate 		/* handle nan cases according to V9 app. B */
121*7c478bd9Sstevel@tonic-gate 		if (QUAD_ISNAN(*y)) {
122*7c478bd9Sstevel@tonic-gate 			if (!(y->l.msw & 0x8000)) {
123*7c478bd9Sstevel@tonic-gate 				/* snan, signal invalid */
124*7c478bd9Sstevel@tonic-gate 				if (fsr & FSR_NVM) {
125*7c478bd9Sstevel@tonic-gate 					__quad_fdivq(x, y, &Z);
126*7c478bd9Sstevel@tonic-gate 				} else {
127*7c478bd9Sstevel@tonic-gate 					Z = *y;
128*7c478bd9Sstevel@tonic-gate 					Z.l.msw |= 0x8000;
129*7c478bd9Sstevel@tonic-gate 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
130*7c478bd9Sstevel@tonic-gate 					    FSR_NVC;
131*7c478bd9Sstevel@tonic-gate 					__quad_setfsrp(&fsr);
132*7c478bd9Sstevel@tonic-gate 				}
133*7c478bd9Sstevel@tonic-gate 				QUAD_RETURN(Z);
134*7c478bd9Sstevel@tonic-gate 			} else if (QUAD_ISNAN(*x) && !(x->l.msw & 0x8000)) {
135*7c478bd9Sstevel@tonic-gate 				/* snan, signal invalid */
136*7c478bd9Sstevel@tonic-gate 				if (fsr & FSR_NVM) {
137*7c478bd9Sstevel@tonic-gate 					__quad_fdivq(x, y, &Z);
138*7c478bd9Sstevel@tonic-gate 				} else {
139*7c478bd9Sstevel@tonic-gate 					Z = *x;
140*7c478bd9Sstevel@tonic-gate 					Z.l.msw |= 0x8000;
141*7c478bd9Sstevel@tonic-gate 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
142*7c478bd9Sstevel@tonic-gate 					    FSR_NVC;
143*7c478bd9Sstevel@tonic-gate 					__quad_setfsrp(&fsr);
144*7c478bd9Sstevel@tonic-gate 				}
145*7c478bd9Sstevel@tonic-gate 				QUAD_RETURN(Z);
146*7c478bd9Sstevel@tonic-gate 			}
147*7c478bd9Sstevel@tonic-gate 			Z = *y;
148*7c478bd9Sstevel@tonic-gate 			QUAD_RETURN(Z);
149*7c478bd9Sstevel@tonic-gate 		}
150*7c478bd9Sstevel@tonic-gate 		if (QUAD_ISNAN(*x)) {
151*7c478bd9Sstevel@tonic-gate 			if (!(x->l.msw & 0x8000)) {
152*7c478bd9Sstevel@tonic-gate 				/* snan, signal invalid */
153*7c478bd9Sstevel@tonic-gate 				if (fsr & FSR_NVM) {
154*7c478bd9Sstevel@tonic-gate 					__quad_fdivq(x, y, &Z);
155*7c478bd9Sstevel@tonic-gate 				} else {
156*7c478bd9Sstevel@tonic-gate 					Z = *x;
157*7c478bd9Sstevel@tonic-gate 					Z.l.msw |= 0x8000;
158*7c478bd9Sstevel@tonic-gate 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
159*7c478bd9Sstevel@tonic-gate 					    FSR_NVC;
160*7c478bd9Sstevel@tonic-gate 					__quad_setfsrp(&fsr);
161*7c478bd9Sstevel@tonic-gate 				}
162*7c478bd9Sstevel@tonic-gate 				QUAD_RETURN(Z);
163*7c478bd9Sstevel@tonic-gate 			}
164*7c478bd9Sstevel@tonic-gate 			Z = *x;
165*7c478bd9Sstevel@tonic-gate 			QUAD_RETURN(Z);
166*7c478bd9Sstevel@tonic-gate 		}
167*7c478bd9Sstevel@tonic-gate 		if (xm == 0x7fff0000) {
168*7c478bd9Sstevel@tonic-gate 			/* x is inf */
169*7c478bd9Sstevel@tonic-gate 			if (ym == 0x7fff0000) {
170*7c478bd9Sstevel@tonic-gate 				/* inf / inf, signal invalid */
171*7c478bd9Sstevel@tonic-gate 				if (fsr & FSR_NVM) {
172*7c478bd9Sstevel@tonic-gate 					__quad_fdivq(x, y, &Z);
173*7c478bd9Sstevel@tonic-gate 				} else {
174*7c478bd9Sstevel@tonic-gate 					Z.l.msw = 0x7fffffff;
175*7c478bd9Sstevel@tonic-gate 					Z.l.frac2 = Z.l.frac3 =
176*7c478bd9Sstevel@tonic-gate 					    Z.l.frac4 = 0xffffffff;
177*7c478bd9Sstevel@tonic-gate 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
178*7c478bd9Sstevel@tonic-gate 					    FSR_NVC;
179*7c478bd9Sstevel@tonic-gate 					__quad_setfsrp(&fsr);
180*7c478bd9Sstevel@tonic-gate 				}
181*7c478bd9Sstevel@tonic-gate 				QUAD_RETURN(Z);
182*7c478bd9Sstevel@tonic-gate 			}
183*7c478bd9Sstevel@tonic-gate 			/* inf / finite, return inf */
184*7c478bd9Sstevel@tonic-gate 			Z.l.msw = sign | 0x7fff0000;
185*7c478bd9Sstevel@tonic-gate 			Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
186*7c478bd9Sstevel@tonic-gate 			QUAD_RETURN(Z);
187*7c478bd9Sstevel@tonic-gate 		}
188*7c478bd9Sstevel@tonic-gate 		/* y is inf */
189*7c478bd9Sstevel@tonic-gate 		Z.l.msw = sign;
190*7c478bd9Sstevel@tonic-gate 		Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
191*7c478bd9Sstevel@tonic-gate 		QUAD_RETURN(Z);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/* handle zero cases */
195*7c478bd9Sstevel@tonic-gate 	if (xm == 0 || ym == 0) {
196*7c478bd9Sstevel@tonic-gate 		if (QUAD_ISZERO(*x)) {
197*7c478bd9Sstevel@tonic-gate 			if (QUAD_ISZERO(*y)) {
198*7c478bd9Sstevel@tonic-gate 				/* zero / zero, signal invalid */
199*7c478bd9Sstevel@tonic-gate 				if (fsr & FSR_NVM) {
200*7c478bd9Sstevel@tonic-gate 					__quad_fdivq(x, y, &Z);
201*7c478bd9Sstevel@tonic-gate 				} else {
202*7c478bd9Sstevel@tonic-gate 					Z.l.msw = 0x7fffffff;
203*7c478bd9Sstevel@tonic-gate 					Z.l.frac2 = Z.l.frac3 =
204*7c478bd9Sstevel@tonic-gate 					    Z.l.frac4 = 0xffffffff;
205*7c478bd9Sstevel@tonic-gate 					fsr = (fsr & ~FSR_CEXC) | FSR_NVA |
206*7c478bd9Sstevel@tonic-gate 					    FSR_NVC;
207*7c478bd9Sstevel@tonic-gate 					__quad_setfsrp(&fsr);
208*7c478bd9Sstevel@tonic-gate 				}
209*7c478bd9Sstevel@tonic-gate 				QUAD_RETURN(Z);
210*7c478bd9Sstevel@tonic-gate 			}
211*7c478bd9Sstevel@tonic-gate 			/* zero / nonzero, return zero */
212*7c478bd9Sstevel@tonic-gate 			Z.l.msw = sign;
213*7c478bd9Sstevel@tonic-gate 			Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
214*7c478bd9Sstevel@tonic-gate 			QUAD_RETURN(Z);
215*7c478bd9Sstevel@tonic-gate 		}
216*7c478bd9Sstevel@tonic-gate 		if (QUAD_ISZERO(*y)) {
217*7c478bd9Sstevel@tonic-gate 			/* nonzero / zero, signal zero divide */
218*7c478bd9Sstevel@tonic-gate 			if (fsr & FSR_DZM) {
219*7c478bd9Sstevel@tonic-gate 				__quad_fdivq(x, y, &Z);
220*7c478bd9Sstevel@tonic-gate 			} else {
221*7c478bd9Sstevel@tonic-gate 				Z.l.msw = sign | 0x7fff0000;
222*7c478bd9Sstevel@tonic-gate 				Z.l.frac2 = Z.l.frac3 = Z.l.frac4 = 0;
223*7c478bd9Sstevel@tonic-gate 				fsr = (fsr & ~FSR_CEXC) | FSR_DZA | FSR_DZC;
224*7c478bd9Sstevel@tonic-gate 				__quad_setfsrp(&fsr);
225*7c478bd9Sstevel@tonic-gate 			}
226*7c478bd9Sstevel@tonic-gate 			QUAD_RETURN(Z);
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	/* now x and y are finite, nonzero */
231*7c478bd9Sstevel@tonic-gate 	__quad_setfsrp(&fsr_re);
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* get their normalized significands and exponents */
234*7c478bd9Sstevel@tonic-gate 	ex = (int)(xm >> 16);
235*7c478bd9Sstevel@tonic-gate 	lx = xm & 0xffff;
236*7c478bd9Sstevel@tonic-gate 	if (ex) {
237*7c478bd9Sstevel@tonic-gate 		lx |= 0x10000;
238*7c478bd9Sstevel@tonic-gate 		wx[0] = x->l.frac2;
239*7c478bd9Sstevel@tonic-gate 		wx[1] = x->l.frac3;
240*7c478bd9Sstevel@tonic-gate 		wx[2] = x->l.frac4;
241*7c478bd9Sstevel@tonic-gate 	} else {
242*7c478bd9Sstevel@tonic-gate 		if (lx | (x->l.frac2 & 0xfffe0000)) {
243*7c478bd9Sstevel@tonic-gate 			wx[0] = x->l.frac2;
244*7c478bd9Sstevel@tonic-gate 			wx[1] = x->l.frac3;
245*7c478bd9Sstevel@tonic-gate 			wx[2] = x->l.frac4;
246*7c478bd9Sstevel@tonic-gate 			ex = 1;
247*7c478bd9Sstevel@tonic-gate 		} else if (x->l.frac2 | (x->l.frac3 & 0xfffe0000)) {
248*7c478bd9Sstevel@tonic-gate 			lx = x->l.frac2;
249*7c478bd9Sstevel@tonic-gate 			wx[0] = x->l.frac3;
250*7c478bd9Sstevel@tonic-gate 			wx[1] = x->l.frac4;
251*7c478bd9Sstevel@tonic-gate 			wx[2] = 0;
252*7c478bd9Sstevel@tonic-gate 			ex = -31;
253*7c478bd9Sstevel@tonic-gate 		} else if (x->l.frac3 | (x->l.frac4 & 0xfffe0000)) {
254*7c478bd9Sstevel@tonic-gate 			lx = x->l.frac3;
255*7c478bd9Sstevel@tonic-gate 			wx[0] = x->l.frac4;
256*7c478bd9Sstevel@tonic-gate 			wx[1] = wx[2] = 0;
257*7c478bd9Sstevel@tonic-gate 			ex = -63;
258*7c478bd9Sstevel@tonic-gate 		} else {
259*7c478bd9Sstevel@tonic-gate 			lx = x->l.frac4;
260*7c478bd9Sstevel@tonic-gate 			wx[0] = wx[1] = wx[2] = 0;
261*7c478bd9Sstevel@tonic-gate 			ex = -95;
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 		while ((lx & 0x10000) == 0) {
264*7c478bd9Sstevel@tonic-gate 			lx = (lx << 1) | (wx[0] >> 31);
265*7c478bd9Sstevel@tonic-gate 			wx[0] = (wx[0] << 1) | (wx[1] >> 31);
266*7c478bd9Sstevel@tonic-gate 			wx[1] = (wx[1] << 1) | (wx[2] >> 31);
267*7c478bd9Sstevel@tonic-gate 			wx[2] <<= 1;
268*7c478bd9Sstevel@tonic-gate 			ex--;
269*7c478bd9Sstevel@tonic-gate 		}
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 	ez = ex;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	ey = (int)(ym >> 16);
274*7c478bd9Sstevel@tonic-gate 	ly = ym & 0xffff;
275*7c478bd9Sstevel@tonic-gate 	if (ey) {
276*7c478bd9Sstevel@tonic-gate 		ly |= 0x10000;
277*7c478bd9Sstevel@tonic-gate 		wy[0] = y->l.frac2;
278*7c478bd9Sstevel@tonic-gate 		wy[1] = y->l.frac3;
279*7c478bd9Sstevel@tonic-gate 		wy[2] = y->l.frac4;
280*7c478bd9Sstevel@tonic-gate 	} else {
281*7c478bd9Sstevel@tonic-gate 		if (ly | (y->l.frac2 & 0xfffe0000)) {
282*7c478bd9Sstevel@tonic-gate 			wy[0] = y->l.frac2;
283*7c478bd9Sstevel@tonic-gate 			wy[1] = y->l.frac3;
284*7c478bd9Sstevel@tonic-gate 			wy[2] = y->l.frac4;
285*7c478bd9Sstevel@tonic-gate 			ey = 1;
286*7c478bd9Sstevel@tonic-gate 		} else if (y->l.frac2 | (y->l.frac3 & 0xfffe0000)) {
287*7c478bd9Sstevel@tonic-gate 			ly = y->l.frac2;
288*7c478bd9Sstevel@tonic-gate 			wy[0] = y->l.frac3;
289*7c478bd9Sstevel@tonic-gate 			wy[1] = y->l.frac4;
290*7c478bd9Sstevel@tonic-gate 			wy[2] = 0;
291*7c478bd9Sstevel@tonic-gate 			ey = -31;
292*7c478bd9Sstevel@tonic-gate 		} else if (y->l.frac3 | (y->l.frac4 & 0xfffe0000)) {
293*7c478bd9Sstevel@tonic-gate 			ly = y->l.frac3;
294*7c478bd9Sstevel@tonic-gate 			wy[0] = y->l.frac4;
295*7c478bd9Sstevel@tonic-gate 			wy[1] = wy[2] = 0;
296*7c478bd9Sstevel@tonic-gate 			ey = -63;
297*7c478bd9Sstevel@tonic-gate 		} else {
298*7c478bd9Sstevel@tonic-gate 			ly = y->l.frac4;
299*7c478bd9Sstevel@tonic-gate 			wy[0] = wy[1] = wy[2] = 0;
300*7c478bd9Sstevel@tonic-gate 			ey = -95;
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 		while ((ly & 0x10000) == 0) {
303*7c478bd9Sstevel@tonic-gate 			ly = (ly << 1) | (wy[0] >> 31);
304*7c478bd9Sstevel@tonic-gate 			wy[0] = (wy[0] << 1) | (wy[1] >> 31);
305*7c478bd9Sstevel@tonic-gate 			wy[1] = (wy[1] << 1) | (wy[2] >> 31);
306*7c478bd9Sstevel@tonic-gate 			wy[2] <<= 1;
307*7c478bd9Sstevel@tonic-gate 			ey--;
308*7c478bd9Sstevel@tonic-gate 		}
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 	ez -= ey - 0x3fff;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/* extract the significands into doubles */
313*7c478bd9Sstevel@tonic-gate 	c = twom16;
314*7c478bd9Sstevel@tonic-gate 	xx[0] = (double)((int)lx) * c;
315*7c478bd9Sstevel@tonic-gate 	yy[0] = (double)((int)ly) * c;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	c *= twom24;
318*7c478bd9Sstevel@tonic-gate 	xx[0] += (double)((int)(wx[0] >> 8)) * c;
319*7c478bd9Sstevel@tonic-gate 	yy[1] = (double)((int)(wy[0] >> 8)) * c;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	c *= twom24;
322*7c478bd9Sstevel@tonic-gate 	xx[1] = (double)((int)(((wx[0] << 16) |
323*7c478bd9Sstevel@tonic-gate 	    (wx[1] >> 16)) & 0xffffff)) * c;
324*7c478bd9Sstevel@tonic-gate 	yy[2] = (double)((int)(((wy[0] << 16) |
325*7c478bd9Sstevel@tonic-gate 	    (wy[1] >> 16)) & 0xffffff)) * c;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	c *= twom24;
328*7c478bd9Sstevel@tonic-gate 	xx[2] = (double)((int)(((wx[1] << 8) |
329*7c478bd9Sstevel@tonic-gate 	    (wx[2] >> 24)) & 0xffffff)) * c;
330*7c478bd9Sstevel@tonic-gate 	yy[3] = (double)((int)(((wy[1] << 8) |
331*7c478bd9Sstevel@tonic-gate 	    (wy[2] >> 24)) & 0xffffff)) * c;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	c *= twom24;
334*7c478bd9Sstevel@tonic-gate 	xx[3] = (double)((int)(wx[2] & 0xffffff)) * c;
335*7c478bd9Sstevel@tonic-gate 	yy[4] = (double)((int)(wy[2] & 0xffffff)) * c;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	/* approximate the reciprocal of y */
338*7c478bd9Sstevel@tonic-gate 	ry = one / ((yy[0] + yy[1]) + yy[2]);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	/* compute the first five "digits" of the quotient */
341*7c478bd9Sstevel@tonic-gate 	zz[0] = (ry * (xx[0] + xx[1]) + three2p27) - three2p27;
342*7c478bd9Sstevel@tonic-gate 	xx[0] = ((xx[0] - zz[0] * yy[0]) - zz[0] * yy[1]) + xx[1];
343*7c478bd9Sstevel@tonic-gate 	d = zz[0] * yy[2];
344*7c478bd9Sstevel@tonic-gate 	c = (d + three2m13) - three2m13;
345*7c478bd9Sstevel@tonic-gate 	xx[0] -= c;
346*7c478bd9Sstevel@tonic-gate 	xx[1] = xx[2] - (d - c);
347*7c478bd9Sstevel@tonic-gate 	d = zz[0] * yy[3];
348*7c478bd9Sstevel@tonic-gate 	c = (d + three2m37) - three2m37;
349*7c478bd9Sstevel@tonic-gate 	xx[1] -= c;
350*7c478bd9Sstevel@tonic-gate 	xx[2] = xx[3] - (d - c);
351*7c478bd9Sstevel@tonic-gate 	d = zz[0] * yy[4];
352*7c478bd9Sstevel@tonic-gate 	c = (d + three2m61) - three2m61;
353*7c478bd9Sstevel@tonic-gate 	xx[2] -= c;
354*7c478bd9Sstevel@tonic-gate 	xx[3] = c - d;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	zz[1] = (ry * (xx[0] + xx[1]) + three2p3) - three2p3;
357*7c478bd9Sstevel@tonic-gate 	xx[0] = ((xx[0] - zz[1] * yy[0]) - zz[1] * yy[1]) + xx[1];
358*7c478bd9Sstevel@tonic-gate 	d = zz[1] * yy[2];
359*7c478bd9Sstevel@tonic-gate 	c = (d + three2m37) - three2m37;
360*7c478bd9Sstevel@tonic-gate 	xx[0] -= c;
361*7c478bd9Sstevel@tonic-gate 	xx[1] = xx[2] - (d - c);
362*7c478bd9Sstevel@tonic-gate 	d = zz[1] * yy[3];
363*7c478bd9Sstevel@tonic-gate 	c = (d + three2m61) - three2m61;
364*7c478bd9Sstevel@tonic-gate 	xx[1] -= c;
365*7c478bd9Sstevel@tonic-gate 	xx[2] = xx[3] - (d - c);
366*7c478bd9Sstevel@tonic-gate 	d = zz[1] * yy[4];
367*7c478bd9Sstevel@tonic-gate 	c = (d + three2m85) - three2m85;
368*7c478bd9Sstevel@tonic-gate 	xx[2] -= c;
369*7c478bd9Sstevel@tonic-gate 	xx[3] = c - d;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	zz[2] = (ry * (xx[0] + xx[1]) + three2m21) - three2m21;
372*7c478bd9Sstevel@tonic-gate 	xx[0] = ((xx[0] - zz[2] * yy[0]) - zz[2] * yy[1]) + xx[1];
373*7c478bd9Sstevel@tonic-gate 	d = zz[2] * yy[2];
374*7c478bd9Sstevel@tonic-gate 	c = (d + three2m61) - three2m61;
375*7c478bd9Sstevel@tonic-gate 	xx[0] -= c;
376*7c478bd9Sstevel@tonic-gate 	xx[1] = xx[2] - (d - c);
377*7c478bd9Sstevel@tonic-gate 	d = zz[2] * yy[3];
378*7c478bd9Sstevel@tonic-gate 	c = (d + three2m85) - three2m85;
379*7c478bd9Sstevel@tonic-gate 	xx[1] -= c;
380*7c478bd9Sstevel@tonic-gate 	xx[2] = xx[3] - (d - c);
381*7c478bd9Sstevel@tonic-gate 	d = zz[2] * yy[4];
382*7c478bd9Sstevel@tonic-gate 	c = (d + three2m109) - three2m109;
383*7c478bd9Sstevel@tonic-gate 	xx[2] -= c;
384*7c478bd9Sstevel@tonic-gate 	xx[3] = c - d;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	zz[3] = (ry * (xx[0] + xx[1]) + three2m45) - three2m45;
387*7c478bd9Sstevel@tonic-gate 	xx[0] = ((xx[0] - zz[3] * yy[0]) - zz[3] * yy[1]) + xx[1];
388*7c478bd9Sstevel@tonic-gate 	d = zz[3] * yy[2];
389*7c478bd9Sstevel@tonic-gate 	c = (d + three2m85) - three2m85;
390*7c478bd9Sstevel@tonic-gate 	xx[0] -= c;
391*7c478bd9Sstevel@tonic-gate 	xx[1] = xx[2] - (d - c);
392*7c478bd9Sstevel@tonic-gate 	d = zz[3] * yy[3];
393*7c478bd9Sstevel@tonic-gate 	c = (d + three2m109) - three2m109;
394*7c478bd9Sstevel@tonic-gate 	xx[1] -= c;
395*7c478bd9Sstevel@tonic-gate 	xx[2] = xx[3] - (d - c);
396*7c478bd9Sstevel@tonic-gate 	d = zz[3] * yy[4];
397*7c478bd9Sstevel@tonic-gate 	c = (d + three2m133) - three2m133;
398*7c478bd9Sstevel@tonic-gate 	xx[2] -= c;
399*7c478bd9Sstevel@tonic-gate 	xx[3] = c - d;
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	zz[4] = (ry * (xx[0] + xx[1]) + three2m73) - three2m73;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	/* reduce to three doubles, making sure zz[1] is positive */
404*7c478bd9Sstevel@tonic-gate 	zz[0] += zz[1] - twom48;
405*7c478bd9Sstevel@tonic-gate 	zz[1] = twom48 + zz[2] + zz[3];
406*7c478bd9Sstevel@tonic-gate 	zz[2] = zz[4];
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	/* if the third term might lie on a rounding boundary, perturb it */
409*7c478bd9Sstevel@tonic-gate 	if (zz[2] == (twom62 + zz[2]) - twom62) {
410*7c478bd9Sstevel@tonic-gate 		/* here we just need to get the sign of the remainder */
411*7c478bd9Sstevel@tonic-gate 		c = (((((xx[0] - zz[4] * yy[0]) - zz[4] * yy[1]) + xx[1]) +
412*7c478bd9Sstevel@tonic-gate 		    (xx[2] - zz[4] * yy[2])) + (xx[3] - zz[4] * yy[3]))
413*7c478bd9Sstevel@tonic-gate 		    - zz[4] * yy[4];
414*7c478bd9Sstevel@tonic-gate 		if (c < zero)
415*7c478bd9Sstevel@tonic-gate 			zz[2] -= twom124;
416*7c478bd9Sstevel@tonic-gate 		else if (c > zero)
417*7c478bd9Sstevel@tonic-gate 			zz[2] += twom124;
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/*
421*7c478bd9Sstevel@tonic-gate 	 * propagate carries/borrows, using round-to-negative-infinity mode
422*7c478bd9Sstevel@tonic-gate 	 * to make all terms nonnegative (note that we can't encounter a
423*7c478bd9Sstevel@tonic-gate 	 * borrow so large that the roundoff is unrepresentable because
424*7c478bd9Sstevel@tonic-gate 	 * we took care to make zz[1] positive above)
425*7c478bd9Sstevel@tonic-gate 	 */
426*7c478bd9Sstevel@tonic-gate 	__quad_setfsrp(&fsr_rn);
427*7c478bd9Sstevel@tonic-gate 	c = zz[1] + zz[2];
428*7c478bd9Sstevel@tonic-gate 	zz[2] += (zz[1] - c);
429*7c478bd9Sstevel@tonic-gate 	zz[1] = c;
430*7c478bd9Sstevel@tonic-gate 	c = zz[0] + zz[1];
431*7c478bd9Sstevel@tonic-gate 	zz[1] += (zz[0] - c);
432*7c478bd9Sstevel@tonic-gate 	zz[0] = c;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	/* check for borrow */
435*7c478bd9Sstevel@tonic-gate 	if (c < one) {
436*7c478bd9Sstevel@tonic-gate 		/* postnormalize */
437*7c478bd9Sstevel@tonic-gate 		zz[0] += zz[0];
438*7c478bd9Sstevel@tonic-gate 		zz[1] += zz[1];
439*7c478bd9Sstevel@tonic-gate 		zz[2] += zz[2];
440*7c478bd9Sstevel@tonic-gate 		ez--;
441*7c478bd9Sstevel@tonic-gate 	}
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	/* if exponent > 0 strip off integer bit, else denormalize */
444*7c478bd9Sstevel@tonic-gate 	if (ez > 0) {
445*7c478bd9Sstevel@tonic-gate 		ibit = 1;
446*7c478bd9Sstevel@tonic-gate 		zz[0] -= one;
447*7c478bd9Sstevel@tonic-gate 	} else {
448*7c478bd9Sstevel@tonic-gate 		ibit = 0;
449*7c478bd9Sstevel@tonic-gate 		if (ez > -128)
450*7c478bd9Sstevel@tonic-gate 			u.l.hi = (unsigned int)(0x3fe + ez) << 20;
451*7c478bd9Sstevel@tonic-gate 		else
452*7c478bd9Sstevel@tonic-gate 			u.l.hi = 0x37e00000;
453*7c478bd9Sstevel@tonic-gate 		u.l.lo = 0;
454*7c478bd9Sstevel@tonic-gate 		zz[0] *= u.d;
455*7c478bd9Sstevel@tonic-gate 		zz[1] *= u.d;
456*7c478bd9Sstevel@tonic-gate 		zz[2] *= u.d;
457*7c478bd9Sstevel@tonic-gate 		ez = 0;
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* the first 48 bits of fraction come from zz[0] */
461*7c478bd9Sstevel@tonic-gate 	u.d = d = two36 + zz[0];
462*7c478bd9Sstevel@tonic-gate 	msw = u.l.lo;
463*7c478bd9Sstevel@tonic-gate 	zz[0] -= (d - two36);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	u.d = d = two4 + zz[0];
466*7c478bd9Sstevel@tonic-gate 	frac2 = u.l.lo;
467*7c478bd9Sstevel@tonic-gate 	zz[0] -= (d - two4);
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/* the next 32 come from zz[0] and zz[1] */
470*7c478bd9Sstevel@tonic-gate 	u.d = d = twom28 + (zz[0] + zz[1]);
471*7c478bd9Sstevel@tonic-gate 	frac3 = u.l.lo;
472*7c478bd9Sstevel@tonic-gate 	zz[0] -= (d - twom28);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	/* condense the remaining fraction; errors here won't matter */
475*7c478bd9Sstevel@tonic-gate 	c = zz[0] + zz[1];
476*7c478bd9Sstevel@tonic-gate 	zz[1] = ((zz[0] - c) + zz[1]) + zz[2];
477*7c478bd9Sstevel@tonic-gate 	zz[0] = c;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	/* get the last word of fraction */
480*7c478bd9Sstevel@tonic-gate 	u.d = d = twom60 + (zz[0] + zz[1]);
481*7c478bd9Sstevel@tonic-gate 	frac4 = u.l.lo;
482*7c478bd9Sstevel@tonic-gate 	zz[0] -= (d - twom60);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/* keep track of what's left for rounding; note that the error */
485*7c478bd9Sstevel@tonic-gate 	/* in computing c will be non-negative due to rounding mode */
486*7c478bd9Sstevel@tonic-gate 	c = zz[0] + zz[1];
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	/* get the rounding mode, fudging directed rounding modes */
489*7c478bd9Sstevel@tonic-gate 	/* as though the result were positive */
490*7c478bd9Sstevel@tonic-gate 	rm = fsr >> 30;
491*7c478bd9Sstevel@tonic-gate 	if (sign)
492*7c478bd9Sstevel@tonic-gate 		rm ^= (rm >> 1);
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	/* round and raise exceptions */
495*7c478bd9Sstevel@tonic-gate 	fsr &= ~FSR_CEXC;
496*7c478bd9Sstevel@tonic-gate 	if (c != zero) {
497*7c478bd9Sstevel@tonic-gate 		fsr |= FSR_NXC;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 		/* decide whether to round the fraction up */
500*7c478bd9Sstevel@tonic-gate 		if (rm == FSR_RP || (rm == FSR_RN && (c > twom113 ||
501*7c478bd9Sstevel@tonic-gate 		    (c == twom113 && ((frac4 & 1) || (c - zz[0] !=
502*7c478bd9Sstevel@tonic-gate 		    zz[1])))))) {
503*7c478bd9Sstevel@tonic-gate 			/* round up and renormalize if necessary */
504*7c478bd9Sstevel@tonic-gate 			if (++frac4 == 0)
505*7c478bd9Sstevel@tonic-gate 				if (++frac3 == 0)
506*7c478bd9Sstevel@tonic-gate 					if (++frac2 == 0)
507*7c478bd9Sstevel@tonic-gate 						if (++msw == 0x10000) {
508*7c478bd9Sstevel@tonic-gate 							msw = 0;
509*7c478bd9Sstevel@tonic-gate 							ez++;
510*7c478bd9Sstevel@tonic-gate 						}
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 	}
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	/* check for under/overflow */
515*7c478bd9Sstevel@tonic-gate 	if (ez >= 0x7fff) {
516*7c478bd9Sstevel@tonic-gate 		if (rm == FSR_RN || rm == FSR_RP) {
517*7c478bd9Sstevel@tonic-gate 			z.l.msw = sign | 0x7fff0000;
518*7c478bd9Sstevel@tonic-gate 			z.l.frac2 = z.l.frac3 = z.l.frac4 = 0;
519*7c478bd9Sstevel@tonic-gate 		} else {
520*7c478bd9Sstevel@tonic-gate 			z.l.msw = sign | 0x7ffeffff;
521*7c478bd9Sstevel@tonic-gate 			z.l.frac2 = z.l.frac3 = z.l.frac4 = 0xffffffff;
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 		fsr |= FSR_OFC | FSR_NXC;
524*7c478bd9Sstevel@tonic-gate 	} else {
525*7c478bd9Sstevel@tonic-gate 		z.l.msw = sign | (ez << 16) | msw;
526*7c478bd9Sstevel@tonic-gate 		z.l.frac2 = frac2;
527*7c478bd9Sstevel@tonic-gate 		z.l.frac3 = frac3;
528*7c478bd9Sstevel@tonic-gate 		z.l.frac4 = frac4;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 		/* !ibit => exact result was tiny before rounding, */
531*7c478bd9Sstevel@tonic-gate 		/* t nonzero => result delivered is inexact */
532*7c478bd9Sstevel@tonic-gate 		if (!ibit) {
533*7c478bd9Sstevel@tonic-gate 			if (c != zero)
534*7c478bd9Sstevel@tonic-gate 				fsr |= FSR_UFC | FSR_NXC;
535*7c478bd9Sstevel@tonic-gate 			else if (fsr & FSR_UFM)
536*7c478bd9Sstevel@tonic-gate 				fsr |= FSR_UFC;
537*7c478bd9Sstevel@tonic-gate 		}
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	if ((fsr & FSR_CEXC) & (fsr >> 23)) {
541*7c478bd9Sstevel@tonic-gate 		__quad_setfsrp(&fsr);
542*7c478bd9Sstevel@tonic-gate 		__quad_fdivq(x, y, &Z);
543*7c478bd9Sstevel@tonic-gate 	} else {
544*7c478bd9Sstevel@tonic-gate 		Z = z;
545*7c478bd9Sstevel@tonic-gate 		fsr |= (fsr & 0x1f) << 5;
546*7c478bd9Sstevel@tonic-gate 		__quad_setfsrp(&fsr);
547*7c478bd9Sstevel@tonic-gate 	}
548*7c478bd9Sstevel@tonic-gate 	QUAD_RETURN(Z);
549*7c478bd9Sstevel@tonic-gate }
550