1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright (c) 1994-1997, by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate * All rights reserved.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate * This file contains __quad_mag_add and __quad_mag_sub, the core
31*0Sstevel@tonic-gate * of the quad precision add and subtract operations.
32*0Sstevel@tonic-gate */
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate #include "quad.h"
35*0Sstevel@tonic-gate
36*0Sstevel@tonic-gate /*
37*0Sstevel@tonic-gate * __quad_mag_add(x, y, z, fsr)
38*0Sstevel@tonic-gate *
39*0Sstevel@tonic-gate * Sets *z = *x + *y, rounded according to the rounding mode in *fsr,
40*0Sstevel@tonic-gate * and updates the current exceptions in *fsr. This routine assumes
41*0Sstevel@tonic-gate * *x and *y are finite, with the same sign (i.e., an addition of
42*0Sstevel@tonic-gate * magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
43*0Sstevel@tonic-gate */
44*0Sstevel@tonic-gate void
__quad_mag_add(const union longdouble * x,const union longdouble * y,union longdouble * z,unsigned int * fsr)45*0Sstevel@tonic-gate __quad_mag_add(const union longdouble *x, const union longdouble *y,
46*0Sstevel@tonic-gate union longdouble *z, unsigned int *fsr)
47*0Sstevel@tonic-gate {
48*0Sstevel@tonic-gate unsigned int lx, ly, ex, ey, frac2, frac3, frac4;
49*0Sstevel@tonic-gate unsigned int round, sticky, carry, rm;
50*0Sstevel@tonic-gate int e, uflo;
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate /* get the leading significand words and exponents */
53*0Sstevel@tonic-gate ex = (x->l.msw & 0x7fffffff) >> 16;
54*0Sstevel@tonic-gate lx = x->l.msw & 0xffff;
55*0Sstevel@tonic-gate if (ex == 0)
56*0Sstevel@tonic-gate ex = 1;
57*0Sstevel@tonic-gate else
58*0Sstevel@tonic-gate lx |= 0x10000;
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate ey = (y->l.msw & 0x7fffffff) >> 16;
61*0Sstevel@tonic-gate ly = y->l.msw & 0xffff;
62*0Sstevel@tonic-gate if (ey == 0)
63*0Sstevel@tonic-gate ey = 1;
64*0Sstevel@tonic-gate else
65*0Sstevel@tonic-gate ly |= 0x10000;
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate /* prenormalize y */
68*0Sstevel@tonic-gate e = (int) ex - (int) ey;
69*0Sstevel@tonic-gate round = sticky = 0;
70*0Sstevel@tonic-gate if (e >= 114) {
71*0Sstevel@tonic-gate frac2 = x->l.frac2;
72*0Sstevel@tonic-gate frac3 = x->l.frac3;
73*0Sstevel@tonic-gate frac4 = x->l.frac4;
74*0Sstevel@tonic-gate sticky = ly | y->l.frac2 | y->l.frac3 | y->l.frac4;
75*0Sstevel@tonic-gate } else {
76*0Sstevel@tonic-gate frac2 = y->l.frac2;
77*0Sstevel@tonic-gate frac3 = y->l.frac3;
78*0Sstevel@tonic-gate frac4 = y->l.frac4;
79*0Sstevel@tonic-gate if (e >= 96) {
80*0Sstevel@tonic-gate sticky = frac4 | frac3 | (frac2 & 0x7fffffff);
81*0Sstevel@tonic-gate round = frac2 & 0x80000000;
82*0Sstevel@tonic-gate frac4 = ly;
83*0Sstevel@tonic-gate frac3 = frac2 = ly = 0;
84*0Sstevel@tonic-gate e -= 96;
85*0Sstevel@tonic-gate } else if (e >= 64) {
86*0Sstevel@tonic-gate sticky = frac4 | (frac3 & 0x7fffffff);
87*0Sstevel@tonic-gate round = frac3 & 0x80000000;
88*0Sstevel@tonic-gate frac4 = frac2;
89*0Sstevel@tonic-gate frac3 = ly;
90*0Sstevel@tonic-gate frac2 = ly = 0;
91*0Sstevel@tonic-gate e -= 64;
92*0Sstevel@tonic-gate } else if (e >= 32) {
93*0Sstevel@tonic-gate sticky = frac4 & 0x7fffffff;
94*0Sstevel@tonic-gate round = frac4 & 0x80000000;
95*0Sstevel@tonic-gate frac4 = frac3;
96*0Sstevel@tonic-gate frac3 = frac2;
97*0Sstevel@tonic-gate frac2 = ly;
98*0Sstevel@tonic-gate ly = 0;
99*0Sstevel@tonic-gate e -= 32;
100*0Sstevel@tonic-gate }
101*0Sstevel@tonic-gate if (e) {
102*0Sstevel@tonic-gate sticky |= round | (frac4 & ((1 << (e - 1)) - 1));
103*0Sstevel@tonic-gate round = frac4 & (1 << (e - 1));
104*0Sstevel@tonic-gate frac4 = (frac4 >> e) | (frac3 << (32 - e));
105*0Sstevel@tonic-gate frac3 = (frac3 >> e) | (frac2 << (32 - e));
106*0Sstevel@tonic-gate frac2 = (frac2 >> e) | (ly << (32 - e));
107*0Sstevel@tonic-gate ly >>= e;
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate /* add, propagating carries */
111*0Sstevel@tonic-gate frac4 += x->l.frac4;
112*0Sstevel@tonic-gate carry = (frac4 < x->l.frac4);
113*0Sstevel@tonic-gate frac3 += x->l.frac3;
114*0Sstevel@tonic-gate if (carry) {
115*0Sstevel@tonic-gate frac3++;
116*0Sstevel@tonic-gate carry = (frac3 <= x->l.frac3);
117*0Sstevel@tonic-gate } else {
118*0Sstevel@tonic-gate carry = (frac3 < x->l.frac3);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate frac2 += x->l.frac2;
121*0Sstevel@tonic-gate if (carry) {
122*0Sstevel@tonic-gate frac2++;
123*0Sstevel@tonic-gate carry = (frac2 <= x->l.frac2);
124*0Sstevel@tonic-gate } else {
125*0Sstevel@tonic-gate carry = (frac2 < x->l.frac2);
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate lx += ly;
128*0Sstevel@tonic-gate if (carry)
129*0Sstevel@tonic-gate lx++;
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate /* postnormalize */
132*0Sstevel@tonic-gate if (lx >= 0x20000) {
133*0Sstevel@tonic-gate sticky |= round;
134*0Sstevel@tonic-gate round = frac4 & 1;
135*0Sstevel@tonic-gate frac4 = (frac4 >> 1) | (frac3 << 31);
136*0Sstevel@tonic-gate frac3 = (frac3 >> 1) | (frac2 << 31);
137*0Sstevel@tonic-gate frac2 = (frac2 >> 1) | (lx << 31);
138*0Sstevel@tonic-gate lx >>= 1;
139*0Sstevel@tonic-gate ex++;
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate /* keep track of whether the result before rounding is tiny */
144*0Sstevel@tonic-gate uflo = (lx < 0x10000);
145*0Sstevel@tonic-gate
146*0Sstevel@tonic-gate /* get the rounding mode, fudging directed rounding modes */
147*0Sstevel@tonic-gate /* as though the result were positive */
148*0Sstevel@tonic-gate rm = *fsr >> 30;
149*0Sstevel@tonic-gate if (z->l.msw)
150*0Sstevel@tonic-gate rm ^= (rm >> 1);
151*0Sstevel@tonic-gate
152*0Sstevel@tonic-gate /* see if we need to round */
153*0Sstevel@tonic-gate if (round | sticky) {
154*0Sstevel@tonic-gate *fsr |= FSR_NXC;
155*0Sstevel@tonic-gate
156*0Sstevel@tonic-gate /* round up if necessary */
157*0Sstevel@tonic-gate if (rm == FSR_RP || (rm == FSR_RN && round &&
158*0Sstevel@tonic-gate (sticky || (frac4 & 1)))) {
159*0Sstevel@tonic-gate if (++frac4 == 0)
160*0Sstevel@tonic-gate if (++frac3 == 0)
161*0Sstevel@tonic-gate if (++frac2 == 0)
162*0Sstevel@tonic-gate if (++lx >= 0x20000) {
163*0Sstevel@tonic-gate lx >>= 1;
164*0Sstevel@tonic-gate ex++;
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate /* check for overflow */
170*0Sstevel@tonic-gate if (ex >= 0x7fff) {
171*0Sstevel@tonic-gate /* store the default overflowed result */
172*0Sstevel@tonic-gate *fsr |= FSR_OFC | FSR_NXC;
173*0Sstevel@tonic-gate if (rm == FSR_RN || rm == FSR_RP) {
174*0Sstevel@tonic-gate z->l.msw |= 0x7fff0000;
175*0Sstevel@tonic-gate z->l.frac2 = z->l.frac3 = z->l.frac4 = 0;
176*0Sstevel@tonic-gate } else {
177*0Sstevel@tonic-gate z->l.msw |= 0x7ffeffff;
178*0Sstevel@tonic-gate z->l.frac2 = z->l.frac3 = z->l.frac4 = 0xffffffff;
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate } else {
181*0Sstevel@tonic-gate /* store the result */
182*0Sstevel@tonic-gate if (lx >= 0x10000)
183*0Sstevel@tonic-gate z->l.msw |= (ex << 16);
184*0Sstevel@tonic-gate z->l.msw |= (lx & 0xffff);
185*0Sstevel@tonic-gate z->l.frac2 = frac2;
186*0Sstevel@tonic-gate z->l.frac3 = frac3;
187*0Sstevel@tonic-gate z->l.frac4 = frac4;
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate /* if the pre-rounded result was tiny and underflow trapping */
190*0Sstevel@tonic-gate /* is enabled, simulate underflow */
191*0Sstevel@tonic-gate if (uflo && (*fsr & FSR_UFM))
192*0Sstevel@tonic-gate *fsr |= FSR_UFC;
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate }
195*0Sstevel@tonic-gate
196*0Sstevel@tonic-gate /*
197*0Sstevel@tonic-gate * __quad_mag_sub(x, y, z, fsr)
198*0Sstevel@tonic-gate *
199*0Sstevel@tonic-gate * Sets *z = *x - *y, rounded according to the rounding mode in *fsr,
200*0Sstevel@tonic-gate * and updates the current exceptions in *fsr. This routine assumes
201*0Sstevel@tonic-gate * *x and *y are finite, with opposite signs (i.e., a subtraction of
202*0Sstevel@tonic-gate * magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
203*0Sstevel@tonic-gate */
204*0Sstevel@tonic-gate void
__quad_mag_sub(const union longdouble * x,const union longdouble * y,union longdouble * z,unsigned int * fsr)205*0Sstevel@tonic-gate __quad_mag_sub(const union longdouble *x, const union longdouble *y,
206*0Sstevel@tonic-gate union longdouble *z, unsigned int *fsr)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate unsigned int lx, ly, ex, ey, frac2, frac3, frac4;
209*0Sstevel@tonic-gate unsigned int guard, round, sticky, borrow, rm;
210*0Sstevel@tonic-gate int e;
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gate /* get the leading significand words and exponents */
213*0Sstevel@tonic-gate ex = (x->l.msw & 0x7fffffff) >> 16;
214*0Sstevel@tonic-gate lx = x->l.msw & 0xffff;
215*0Sstevel@tonic-gate if (ex == 0)
216*0Sstevel@tonic-gate ex = 1;
217*0Sstevel@tonic-gate else
218*0Sstevel@tonic-gate lx |= 0x10000;
219*0Sstevel@tonic-gate
220*0Sstevel@tonic-gate ey = (y->l.msw & 0x7fffffff) >> 16;
221*0Sstevel@tonic-gate ly = y->l.msw & 0xffff;
222*0Sstevel@tonic-gate if (ey == 0)
223*0Sstevel@tonic-gate ey = 1;
224*0Sstevel@tonic-gate else
225*0Sstevel@tonic-gate ly |= 0x10000;
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate /* prenormalize y */
228*0Sstevel@tonic-gate e = (int) ex - (int) ey;
229*0Sstevel@tonic-gate guard = round = sticky = 0;
230*0Sstevel@tonic-gate if (e > 114) {
231*0Sstevel@tonic-gate sticky = ly | y->l.frac2 | y->l.frac3 | y->l.frac4;
232*0Sstevel@tonic-gate ly = frac2 = frac3 = frac4 = 0;
233*0Sstevel@tonic-gate } else {
234*0Sstevel@tonic-gate frac2 = y->l.frac2;
235*0Sstevel@tonic-gate frac3 = y->l.frac3;
236*0Sstevel@tonic-gate frac4 = y->l.frac4;
237*0Sstevel@tonic-gate if (e >= 96) {
238*0Sstevel@tonic-gate sticky = frac4 | frac3 | (frac2 & 0x3fffffff);
239*0Sstevel@tonic-gate round = frac2 & 0x40000000;
240*0Sstevel@tonic-gate guard = frac2 & 0x80000000;
241*0Sstevel@tonic-gate frac4 = ly;
242*0Sstevel@tonic-gate frac3 = frac2 = ly = 0;
243*0Sstevel@tonic-gate e -= 96;
244*0Sstevel@tonic-gate } else if (e >= 64) {
245*0Sstevel@tonic-gate sticky = frac4 | (frac3 & 0x3fffffff);
246*0Sstevel@tonic-gate round = frac3 & 0x40000000;
247*0Sstevel@tonic-gate guard = frac3 & 0x80000000;
248*0Sstevel@tonic-gate frac4 = frac2;
249*0Sstevel@tonic-gate frac3 = ly;
250*0Sstevel@tonic-gate frac2 = ly = 0;
251*0Sstevel@tonic-gate e -= 64;
252*0Sstevel@tonic-gate } else if (e >= 32) {
253*0Sstevel@tonic-gate sticky = frac4 & 0x3fffffff;
254*0Sstevel@tonic-gate round = frac4 & 0x40000000;
255*0Sstevel@tonic-gate guard = frac4 & 0x80000000;
256*0Sstevel@tonic-gate frac4 = frac3;
257*0Sstevel@tonic-gate frac3 = frac2;
258*0Sstevel@tonic-gate frac2 = ly;
259*0Sstevel@tonic-gate ly = 0;
260*0Sstevel@tonic-gate e -= 32;
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate if (e > 1) {
263*0Sstevel@tonic-gate sticky |= guard | round |
264*0Sstevel@tonic-gate (frac4 & ((1 << (e - 2)) - 1));
265*0Sstevel@tonic-gate round = frac4 & (1 << (e - 2));
266*0Sstevel@tonic-gate guard = frac4 & (1 << (e - 1));
267*0Sstevel@tonic-gate frac4 = (frac4 >> e) | (frac3 << (32 - e));
268*0Sstevel@tonic-gate frac3 = (frac3 >> e) | (frac2 << (32 - e));
269*0Sstevel@tonic-gate frac2 = (frac2 >> e) | (ly << (32 - e));
270*0Sstevel@tonic-gate ly >>= e;
271*0Sstevel@tonic-gate } else if (e == 1) {
272*0Sstevel@tonic-gate sticky |= round;
273*0Sstevel@tonic-gate round = guard;
274*0Sstevel@tonic-gate guard = frac4 & 1;
275*0Sstevel@tonic-gate frac4 = (frac4 >> 1) | (frac3 << 31);
276*0Sstevel@tonic-gate frac3 = (frac3 >> 1) | (frac2 << 31);
277*0Sstevel@tonic-gate frac2 = (frac2 >> 1) | (ly << 31);
278*0Sstevel@tonic-gate ly >>= 1;
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate /* complement guard, round, and sticky as need be */
283*0Sstevel@tonic-gate if (sticky) {
284*0Sstevel@tonic-gate round = !round;
285*0Sstevel@tonic-gate guard = !guard;
286*0Sstevel@tonic-gate } else if (round) {
287*0Sstevel@tonic-gate guard = !guard;
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate borrow = (guard | round | sticky);
290*0Sstevel@tonic-gate
291*0Sstevel@tonic-gate /* subtract, propagating borrows */
292*0Sstevel@tonic-gate frac4 = x->l.frac4 - frac4;
293*0Sstevel@tonic-gate if (borrow) {
294*0Sstevel@tonic-gate frac4--;
295*0Sstevel@tonic-gate borrow = (frac4 >= x->l.frac4);
296*0Sstevel@tonic-gate } else {
297*0Sstevel@tonic-gate borrow = (frac4 > x->l.frac4);
298*0Sstevel@tonic-gate }
299*0Sstevel@tonic-gate frac3 = x->l.frac3 - frac3;
300*0Sstevel@tonic-gate if (borrow) {
301*0Sstevel@tonic-gate frac3--;
302*0Sstevel@tonic-gate borrow = (frac3 >= x->l.frac3);
303*0Sstevel@tonic-gate } else {
304*0Sstevel@tonic-gate borrow = (frac3 > x->l.frac3);
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate frac2 = x->l.frac2 - frac2;
307*0Sstevel@tonic-gate if (borrow) {
308*0Sstevel@tonic-gate frac2--;
309*0Sstevel@tonic-gate borrow = (frac2 >= x->l.frac2);
310*0Sstevel@tonic-gate } else {
311*0Sstevel@tonic-gate borrow = (frac2 > x->l.frac2);
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate lx -= ly;
314*0Sstevel@tonic-gate if (borrow)
315*0Sstevel@tonic-gate lx--;
316*0Sstevel@tonic-gate
317*0Sstevel@tonic-gate /* get the rounding mode */
318*0Sstevel@tonic-gate rm = *fsr >> 30;
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate /* handle zero result */
321*0Sstevel@tonic-gate if (!(lx | frac2 | frac3 | frac4 | guard)) {
322*0Sstevel@tonic-gate z->l.msw = ((rm == FSR_RM)? 0x80000000 : 0);
323*0Sstevel@tonic-gate z->l.frac2 = z->l.frac3 = z->l.frac4 = 0;
324*0Sstevel@tonic-gate return;
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate /* postnormalize */
328*0Sstevel@tonic-gate if (lx < 0x10000) {
329*0Sstevel@tonic-gate /* if cancellation occurred or the exponent is 1, */
330*0Sstevel@tonic-gate /* the result is exact */
331*0Sstevel@tonic-gate if (lx < 0x8000 || ex == 1) {
332*0Sstevel@tonic-gate while ((lx | (frac2 & 0xfffe0000)) == 0 && ex > 32) {
333*0Sstevel@tonic-gate lx = frac2;
334*0Sstevel@tonic-gate frac2 = frac3;
335*0Sstevel@tonic-gate frac3 = frac4;
336*0Sstevel@tonic-gate frac4 = ((guard)? 0x80000000 : 0);
337*0Sstevel@tonic-gate guard = 0;
338*0Sstevel@tonic-gate ex -= 32;
339*0Sstevel@tonic-gate }
340*0Sstevel@tonic-gate while (lx < 0x10000 && ex > 1) {
341*0Sstevel@tonic-gate lx = (lx << 1) | (frac2 >> 31);
342*0Sstevel@tonic-gate frac2 = (frac2 << 1) | (frac3 >> 31);
343*0Sstevel@tonic-gate frac3 = (frac3 << 1) | (frac4 >> 31);
344*0Sstevel@tonic-gate frac4 <<= 1;
345*0Sstevel@tonic-gate if (guard) {
346*0Sstevel@tonic-gate frac4 |= 1;
347*0Sstevel@tonic-gate guard = 0;
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate ex--;
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate if (lx >= 0x10000)
352*0Sstevel@tonic-gate z->l.msw |= (ex << 16);
353*0Sstevel@tonic-gate z->l.msw |= (lx & 0xffff);
354*0Sstevel@tonic-gate z->l.frac2 = frac2;
355*0Sstevel@tonic-gate z->l.frac3 = frac3;
356*0Sstevel@tonic-gate z->l.frac4 = frac4;
357*0Sstevel@tonic-gate
358*0Sstevel@tonic-gate /* if the result is tiny and underflow trapping is */
359*0Sstevel@tonic-gate /* enabled, simulate underflow */
360*0Sstevel@tonic-gate if (lx < 0x10000 && (*fsr & FSR_UFM))
361*0Sstevel@tonic-gate *fsr |= FSR_UFC;
362*0Sstevel@tonic-gate return;
363*0Sstevel@tonic-gate }
364*0Sstevel@tonic-gate
365*0Sstevel@tonic-gate /* otherwise we only borrowed one place */
366*0Sstevel@tonic-gate lx = (lx << 1) | (frac2 >> 31);
367*0Sstevel@tonic-gate frac2 = (frac2 << 1) | (frac3 >> 31);
368*0Sstevel@tonic-gate frac3 = (frac3 << 1) | (frac4 >> 31);
369*0Sstevel@tonic-gate frac4 <<= 1;
370*0Sstevel@tonic-gate if (guard)
371*0Sstevel@tonic-gate frac4 |= 1;
372*0Sstevel@tonic-gate ex--;
373*0Sstevel@tonic-gate } else {
374*0Sstevel@tonic-gate sticky |= round;
375*0Sstevel@tonic-gate round = guard;
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate
378*0Sstevel@tonic-gate /* fudge directed rounding modes as though the result were positive */
379*0Sstevel@tonic-gate if (z->l.msw)
380*0Sstevel@tonic-gate rm ^= (rm >> 1);
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gate /* see if we need to round */
383*0Sstevel@tonic-gate if (round | sticky) {
384*0Sstevel@tonic-gate *fsr |= FSR_NXC;
385*0Sstevel@tonic-gate
386*0Sstevel@tonic-gate /* round up if necessary */
387*0Sstevel@tonic-gate if (rm == FSR_RP || (rm == FSR_RN && round &&
388*0Sstevel@tonic-gate (sticky || (frac4 & 1)))) {
389*0Sstevel@tonic-gate if (++frac4 == 0)
390*0Sstevel@tonic-gate if (++frac3 == 0)
391*0Sstevel@tonic-gate if (++frac2 == 0)
392*0Sstevel@tonic-gate if (++lx >= 0x20000) {
393*0Sstevel@tonic-gate lx >>= 1;
394*0Sstevel@tonic-gate ex++;
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate }
398*0Sstevel@tonic-gate
399*0Sstevel@tonic-gate /* store the result */
400*0Sstevel@tonic-gate z->l.msw |= (ex << 16) | (lx & 0xffff);
401*0Sstevel@tonic-gate z->l.frac2 = frac2;
402*0Sstevel@tonic-gate z->l.frac3 = frac3;
403*0Sstevel@tonic-gate z->l.frac4 = frac4;
404*0Sstevel@tonic-gate }
405