/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994-1997, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains __quad_mag_add and __quad_mag_sub, the core
* of the quad precision add and subtract operations.
*/
#include "quad.h"
/*
* __quad_mag_add(x, y, z, fsr)
*
* Sets *z = *x + *y, rounded according to the rounding mode in *fsr,
* and updates the current exceptions in *fsr. This routine assumes
* *x and *y are finite, with the same sign (i.e., an addition of
* magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
*/
void
union longdouble *z, unsigned int *fsr)
{
int e, uflo;
/* get the leading significand words and exponents */
if (ex == 0)
ex = 1;
else
lx |= 0x10000;
if (ey == 0)
ey = 1;
else
ly |= 0x10000;
/* prenormalize y */
if (e >= 114) {
} else {
if (e >= 96) {
e -= 96;
} else if (e >= 64) {
e -= 64;
} else if (e >= 32) {
ly = 0;
e -= 32;
}
if (e) {
ly >>= e;
}
/* add, propagating carries */
if (carry) {
frac3++;
} else {
}
if (carry) {
frac2++;
} else {
}
if (carry)
lx++;
/* postnormalize */
if (lx >= 0x20000) {
lx >>= 1;
ex++;
}
}
/* keep track of whether the result before rounding is tiny */
/* get the rounding mode, fudging directed rounding modes */
/* as though the result were positive */
if (z->l.msw)
/* see if we need to round */
/* round up if necessary */
if (++frac4 == 0)
if (++frac3 == 0)
if (++frac2 == 0)
if (++lx >= 0x20000) {
lx >>= 1;
ex++;
}
}
}
/* check for overflow */
if (ex >= 0x7fff) {
/* store the default overflowed result */
z->l.msw |= 0x7fff0000;
} else {
z->l.msw |= 0x7ffeffff;
}
} else {
/* store the result */
if (lx >= 0x10000)
/* if the pre-rounded result was tiny and underflow trapping */
/* is enabled, simulate underflow */
}
}
/*
* __quad_mag_sub(x, y, z, fsr)
*
* Sets *z = *x - *y, rounded according to the rounding mode in *fsr,
* and updates the current exceptions in *fsr. This routine assumes
* *x and *y are finite, with opposite signs (i.e., a subtraction of
* magnitudes), |*x| >= |*y|, and *z already has its sign bit set.
*/
void
union longdouble *z, unsigned int *fsr)
{
int e;
/* get the leading significand words and exponents */
if (ex == 0)
ex = 1;
else
lx |= 0x10000;
if (ey == 0)
ey = 1;
else
ly |= 0x10000;
/* prenormalize y */
if (e > 114) {
} else {
if (e >= 96) {
e -= 96;
} else if (e >= 64) {
e -= 64;
} else if (e >= 32) {
ly = 0;
e -= 32;
}
if (e > 1) {
ly >>= e;
} else if (e == 1) {
ly >>= 1;
}
}
/* complement guard, round, and sticky as need be */
if (sticky) {
} else if (round) {
}
/* subtract, propagating borrows */
if (borrow) {
frac4--;
} else {
}
if (borrow) {
frac3--;
} else {
}
if (borrow) {
frac2--;
} else {
}
if (borrow)
lx--;
/* get the rounding mode */
/* handle zero result */
return;
}
/* postnormalize */
if (lx < 0x10000) {
/* if cancellation occurred or the exponent is 1, */
/* the result is exact */
guard = 0;
ex -= 32;
}
frac4 <<= 1;
if (guard) {
frac4 |= 1;
guard = 0;
}
ex--;
}
if (lx >= 0x10000)
/* if the result is tiny and underflow trapping is */
/* enabled, simulate underflow */
return;
}
/* otherwise we only borrowed one place */
frac4 <<= 1;
if (guard)
frac4 |= 1;
ex--;
} else {
}
/* fudge directed rounding modes as though the result were positive */
if (z->l.msw)
/* see if we need to round */
/* round up if necessary */
if (++frac4 == 0)
if (++frac3 == 0)
if (++frac2 == 0)
if (++lx >= 0x20000) {
lx >>= 1;
ex++;
}
}
}
/* store the result */
}