Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     23 
     24 /*
     25  * Copyright (c) 1988 by Sun Microsystems, Inc.
     26  */
     27 
     28 #include "_Qquad.h"
     29 #include "_Qglobals.h"
     30 
     31 PRIVATE void
     32 true_add(px, py, pz)
     33 	unpacked       *px, *py, *pz;
     34 
     35 {
     36 	unsigned 	c;
     37 	unpacked       *pt;
     38 
     39 	if ((int) px->fpclass < (int) py->fpclass) {	/* Reverse. */
     40 		pt = py;
     41 		py = px;
     42 		px = pt;
     43 	}
     44 	/* Now class(x) >= class(y). */
     45 	switch (px->fpclass) {
     46 	case fp_quiet:		/* NaN + x -> NaN */
     47 	case fp_signaling:	/* NaN + x -> NaN */
     48 	case fp_infinity:	/* Inf + x -> Inf */
     49 	case fp_zero:		/* 0 + 0 -> 0 */
     50 		*pz = *px;
     51 		return;
     52 	default:
     53 		if (py->fpclass == fp_zero) {
     54 			*pz = *px;
     55 			return;
     56 		}
     57 	}
     58 	/* Now z is normal or subnormal. */
     59 	/* Now y is normal or subnormal. */
     60 	if (px->exponent < py->exponent) {	/* Reverse. */
     61 		pt = py;
     62 		py = px;
     63 		px = pt;
     64 	}
     65 	/* Now class(x) >= class(y). */
     66 	pz->fpclass = px->fpclass;
     67 	pz->sign = px->sign;
     68 	pz->exponent = px->exponent;
     69 	pz->rounded = pz->sticky  = 0;
     70 
     71 	if (px->exponent != py->exponent) {	/* pre-alignment required */
     72 		fpu_rightshift(py, pz->exponent - py->exponent);
     73 		pz->rounded = py->rounded;
     74 		pz->sticky  = py->sticky;
     75 	}
     76 	c = 0;
     77 	c = fpu_add3wc(&(pz->significand[3]),px->significand[3],
     78 						py->significand[3],c);
     79 	c = fpu_add3wc(&(pz->significand[2]),px->significand[2],
     80 						py->significand[2],c);
     81 	c = fpu_add3wc(&(pz->significand[1]),px->significand[1],
     82 						py->significand[1],c);
     83 	c = fpu_add3wc(&(pz->significand[0]),px->significand[0],
     84 						py->significand[0],c);
     85 
     86 	/* Handle carry out of msb. */
     87 	if(pz->significand[0]>=0x20000) {
     88 		fpu_rightshift(pz, 1);	/* Carried out bit. */
     89 		pz->exponent ++;	/* Renormalize. */
     90 	}
     91 	return;
     92 }
     93 
     94 PRIVATE void
     95 true_sub(px, py, pz)
     96 	unpacked       *px, *py, *pz;
     97 
     98 {
     99 	unsigned       *z,g,s,r,c;
    100 	int	       n;
    101 	unpacked       *pt;
    102 
    103 	if ((int) px->fpclass < (int) py->fpclass) {	/* Reverse. */
    104 		pt = py;
    105 		py = px;
    106 		px = pt;
    107 	}
    108 	/* Now class(x) >= class(y). */
    109 	*pz = *px;		/* Tentative difference: x. */
    110 	switch (pz->fpclass) {
    111 	case fp_quiet:		/* NaN - x -> NaN */
    112 	case fp_signaling:	/* NaN - x -> NaN */
    113 		return;
    114 	case fp_infinity:	/* Inf - x -> Inf */
    115 		if (py->fpclass == fp_infinity) {
    116 			fpu_error_nan(pz);	/* Inf - Inf -> NaN */
    117 			pz->fpclass = fp_quiet;
    118 		}
    119 		return;
    120 	case fp_zero:		/* 0 - 0 -> 0 */
    121 		pz->sign = (fp_direction == fp_negative);
    122 		return;
    123 	default:
    124 		if (py->fpclass == fp_zero)
    125 			return;
    126 	}
    127 
    128 	/* x and y are both normal or subnormal. */
    129 
    130 	if (px->exponent < py->exponent) { /* Reverse. */
    131 		pt = py;
    132 		py = px;
    133 		px = pt;
    134 	}
    135 	/* Now exp(x) >= exp(y). */
    136 	pz->fpclass = px->fpclass;
    137 	pz->sign = px->sign;
    138 	pz->exponent = px->exponent;
    139 	pz->rounded = 0;
    140 	pz->sticky = 0;
    141 	z = pz->significand;
    142 
    143 	if (px->exponent == py->exponent) {	/* no pre-alignment required */
    144 		c = 0;
    145 		c = fpu_sub3wc(&z[3],px->significand[3],py->significand[3],c);
    146 		c = fpu_sub3wc(&z[2],px->significand[2],py->significand[2],c);
    147 		c = fpu_sub3wc(&z[1],px->significand[1],py->significand[1],c);
    148 		c = fpu_sub3wc(&z[0],px->significand[0],py->significand[0],c);
    149 		if((z[0]|z[1]|z[2]|z[3])==0) {		/* exact zero result */
    150 			pz->sign = (fp_direction == fp_negative);
    151 			pz->fpclass = fp_zero;
    152 			return;
    153 		}
    154 		if(z[0]>=0x20000) {	/* sign reversal occurred */
    155 			pz->sign = py->sign;
    156 			c = 0;
    157 			c = fpu_neg2wc(&z[3],z[3],c);
    158 			c = fpu_neg2wc(&z[2],z[2],c);
    159 			c = fpu_neg2wc(&z[1],z[1],c);
    160 			c = fpu_neg2wc(&z[0],z[0],c);
    161 		}
    162 		fpu_normalize(pz);
    163 		return;
    164 	} else {		/* pre-alignment required */
    165 		fpu_rightshift(py, pz->exponent - py->exponent - 1);
    166 		r = py->rounded; 	/* rounded bit */
    167 		s = py->sticky;		/* sticky bit */
    168 		fpu_rightshift(py, 1);
    169 		g = py->rounded;	/* guard bit */
    170 		if(s!=0) r = (r==0);
    171 		if((r|s)!=0) g = (g==0);/* guard and rounded bits of z */
    172 		c = ((g|r|s)!=0);
    173 		c = fpu_sub3wc(&z[3],px->significand[3],py->significand[3],c);
    174 		c = fpu_sub3wc(&z[2],px->significand[2],py->significand[2],c);
    175 		c = fpu_sub3wc(&z[1],px->significand[1],py->significand[1],c);
    176 		c = fpu_sub3wc(&z[0],px->significand[0],py->significand[0],c);
    177 
    178 		if(z[0]>=0x10000) { 	/* don't need post-shifted */
    179 			pz->sticky = s|r;
    180 			pz->rounded = g;
    181 		} else {		/* post-shifted left 1 bit */
    182 			pz->sticky = s;
    183 			pz->rounded = r;
    184 			pz->significand[0] = (z[0]<<1)|((z[1]&0x80000000)>>31);
    185 			pz->significand[1] = (z[1]<<1)|((z[2]&0x80000000)>>31);
    186 			pz->significand[2] = (z[2]<<1)|((z[3]&0x80000000)>>31);
    187 			pz->significand[3] = (z[3]<<1)|g;
    188 			pz->exponent      -= 1;
    189 			if(z[0]<0x10000) fpu_normalize(pz);
    190 		}
    191 		return;
    192 	}
    193 }
    194 
    195 void
    196 _fp_add(px, py, pz)
    197 	unpacked       *px, *py, *pz;
    198 
    199 {
    200 	if (px->sign == py->sign)
    201 		true_add(px, py, pz);
    202 	else
    203 		true_sub(px, py, pz);
    204 }
    205 
    206 void
    207 _fp_sub(px, py, pz)
    208 	unpacked       *px, *py, *pz;
    209 
    210 {
    211 	py->sign = 1 - py->sign;
    212 	if (px->sign == py->sign)
    213 		true_add(px, py, pz);
    214 	else
    215 		true_sub(px, py, pz);
    216 }
    217