📄 ieee.c
字号:
eshup1(equot); equot[NI-2] |= j; eshup1(num); } goto divdon; }/* The number of quotient bits to calculate is * NBITS + 1 scaling guard bit + 1 roundoff bit. */fulldiv:p = &equot[NI-2];for( i=0; i<NBITS+2; i++ ) { if( ecmpm(den,num) <= 0 ) { esubm(den, num); j = 1; /* quotient bit = 1 */ } else j = 0; eshup1(equot); *p |= j; eshup1(num); }divdon:eshdn1( equot );eshdn1( equot );/* test for nonzero remainder after roundoff bit */p = &num[M];j = 0;for( i=M; i<NI; i++ ) { j |= *p++; }if( j ) j = 1;for( i=0; i<NI; i++ ) num[i] = equot[i];return( (int )j );}/* Multiply significands */int emulm( a, b )unsigned short a[], b[];{unsigned short *p, *q;int i, j, k;equot[0] = b[0];equot[1] = b[1];for( i=M; i<NI; i++ ) equot[i] = 0;p = &a[NI-2];k = NBITS;while( *p == 0 ) /* significand is not supposed to be all zero */ { eshdn6(a); k -= 16; }if( (*p & 0xff) == 0 ) { eshdn8(a); k -= 8; }q = &equot[NI-1];j = 0;for( i=0; i<k; i++ ) { if( *p & 1 ) eaddm(b, equot);/* remember if there were any nonzero bits shifted out */ if( *q & 1 ) j |= 1; eshdn1(a); eshdn1(equot); }for( i=0; i<NI; i++ ) b[i] = equot[i];/* return flag for lost nonzero bits */return(j);}#else/* Multiply significand of e-type number bby 16-bit quantity a, e-type result to c. */void m16m( a, b, c )unsigned short a;unsigned short b[], c[];{register unsigned short *pp;register unsigned long carry;unsigned short *ps;unsigned short p[NI];unsigned long aa, m;int i;aa = a;pp = &p[NI-2];*pp++ = 0;*pp = 0;ps = &b[NI-1];for( i=M+1; i<NI; i++ ) { if( *ps == 0 ) { --ps; --pp; *(pp-1) = 0; } else { m = (unsigned long) aa * *ps--; carry = (m & 0xffff) + *pp; *pp-- = (unsigned short )carry; carry = (carry >> 16) + (m >> 16) + *pp; *pp = (unsigned short )carry; *(pp-1) = carry >> 16; } }for( i=M; i<NI; i++ ) c[i] = p[i];}/* Divide significands. Neither the numerator nor the denominatoris permitted to have its high guard word nonzero. */int edivm( den, num )unsigned short den[], num[];{int i;register unsigned short *p;unsigned long tnum;unsigned short j, tdenm, tquot;unsigned short tprod[NI+1];p = &equot[0];*p++ = num[0];*p++ = num[1];for( i=M; i<NI; i++ ) { *p++ = 0; }eshdn1( num );tdenm = den[M+1];for( i=M; i<NI; i++ ) { /* Find trial quotient digit (the radix is 65536). */ tnum = (((unsigned long) num[M]) << 16) + num[M+1]; /* Do not execute the divide instruction if it will overflow. */ if( (tdenm * 0xffffL) < tnum ) tquot = 0xffff; else tquot = tnum / tdenm; /* Prove that the divide worked. *//* tcheck = (unsigned long )tquot * tdenm; if( tnum - tcheck > tdenm ) tquot = 0xffff;*/ /* Multiply denominator by trial quotient digit. */ m16m( tquot, den, tprod ); /* The quotient digit may have been overestimated. */ if( ecmpm( tprod, num ) > 0 ) { tquot -= 1; esubm( den, tprod ); if( ecmpm( tprod, num ) > 0 ) { tquot -= 1; esubm( den, tprod ); } }/* if( ecmpm( tprod, num ) > 0 ) { eshow( "tprod", tprod ); eshow( "num ", num ); printf( "tnum = %08lx, tden = %04x, tquot = %04x\n", tnum, den[M+1], tquot ); }*/ esubm( tprod, num );/* if( ecmpm( num, den ) >= 0 ) { eshow( "num ", num ); eshow( "den ", den ); printf( "tnum = %08lx, tden = %04x, tquot = %04x\n", tnum, den[M+1], tquot ); }*/ equot[i] = tquot; eshup6(num); }/* test for nonzero remainder after roundoff bit */p = &num[M];j = 0;for( i=M; i<NI; i++ ) { j |= *p++; }if( j ) j = 1;for( i=0; i<NI; i++ ) num[i] = equot[i];return( (int )j );}/* Multiply significands */int emulm( a, b )unsigned short a[], b[];{unsigned short *p, *q;unsigned short pprod[NI];unsigned short j;int i;equot[0] = b[0];equot[1] = b[1];for( i=M; i<NI; i++ ) equot[i] = 0;j = 0;p = &a[NI-1];q = &equot[NI-1];for( i=M+1; i<NI; i++ ) { if( *p == 0 ) { --p; } else { m16m( *p--, b, pprod ); eaddm(pprod, equot); } j |= *q; eshdn6(equot); }for( i=0; i<NI; i++ ) b[i] = equot[i];/* return flag for lost nonzero bits */return( (int)j );}/*eshow(str, x)char *str;unsigned short *x;{int i;printf( "%s ", str );for( i=0; i<NI; i++ ) printf( "%04x ", *x++ );printf( "\n" );}*/#endif/* * Normalize and round off. * * The internal format number to be rounded is "s". * Input "lost" indicates whether the number is exact. * This is the so-called sticky bit. * * Input "subflg" indicates whether the number was obtained * by a subtraction operation. In that case if lost is nonzero * then the number is slightly smaller than indicated. * * Input "exp" is the biased exponent, which may be negative. * the exponent field of "s" is ignored but is replaced by * "exp" as adjusted by normalization and rounding. * * Input "rcntrl" is the rounding control. */static int rlast = -1;static int rw = 0;static unsigned short rmsk = 0;static unsigned short rmbit = 0;static unsigned short rebit = 0;static int re = 0;static unsigned short rbit[NI] = {0,0,0,0,0,0,0,0};void emdnorm( s, lost, subflg, exp, rcntrl )unsigned short s[];int lost;int subflg;long exp;int rcntrl;{int i, j;unsigned short r;/* Normalize */j = enormlz( s );/* a blank significand could mean either zero or infinity. */#ifndef INFINITIESif( j > NBITS ) { ecleazs( s ); return; }#endifexp -= j;#ifndef INFINITIESif( exp >= 32767L ) goto overf;#elseif( (j > NBITS) && (exp < 32767L) ) { ecleazs( s ); return; }#endifif( exp < 0L ) { if( exp > (long )(-NBITS-1) ) { j = (int )exp; i = eshift( s, j ); if( i ) lost = 1; } else { ecleazs( s ); return; } }/* Round off, unless told not to by rcntrl. */if( rcntrl == 0 ) goto mdfin;/* Set up rounding parameters if the control register changed. */if( rndprc != rlast ) { ecleaz( rbit ); switch( rndprc ) { default: case NBITS: rw = NI-1; /* low guard word */ rmsk = 0xffff; rmbit = 0x8000; rebit = 1; re = rw - 1; break; case 113: rw = 10; rmsk = 0x7fff; rmbit = 0x4000; rebit = 0x8000; re = rw; break; case 64: rw = 7; rmsk = 0xffff; rmbit = 0x8000; rebit = 1; re = rw-1; break;/* For DEC arithmetic */ case 56: rw = 6; rmsk = 0xff; rmbit = 0x80; rebit = 0x100; re = rw; break; case 53: rw = 6; rmsk = 0x7ff; rmbit = 0x0400; rebit = 0x800; re = rw; break; case 24: rw = 4; rmsk = 0xff; rmbit = 0x80; rebit = 0x100; re = rw; break; } rbit[re] = rebit; rlast = rndprc; }/* Shift down 1 temporarily if the data structure has an implied * most significant bit and the number is denormal. * For rndprc = 64 or NBITS, there is no implied bit. * But Intel long double denormals lose one bit of significance even so. */#ifdef IBMPCif( (exp <= 0) && (rndprc != NBITS) )#elseif( (exp <= 0) && (rndprc != 64) && (rndprc != NBITS) )#endif { lost |= s[NI-1] & 1; eshdn1(s); }/* Clear out all bits below the rounding bit, * remembering in r if any were nonzero. */r = s[rw] & rmsk;if( rndprc < NBITS ) { i = rw + 1; while( i < NI ) { if( s[i] ) r |= 1; s[i] = 0; ++i; } }s[rw] &= ~rmsk;if( (r & rmbit) != 0 ) { if( r == rmbit ) { if( lost == 0 ) { /* round to even */ if( (s[re] & rebit) == 0 ) goto mddone; } else { if( subflg != 0 ) goto mddone; } } eaddm( rbit, s ); }mddone:#ifdef IBMPCif( (exp <= 0) && (rndprc != NBITS) )#elseif( (exp <= 0) && (rndprc != 64) && (rndprc != NBITS) )#endif { eshup1(s); }if( s[2] != 0 ) { /* overflow on roundoff */ eshdn1(s); exp += 1; }mdfin:s[NI-1] = 0;if( exp >= 32767L ) {#ifndef INFINITIESoverf:#endif#ifdef INFINITIES s[1] = 32767; for( i=2; i<NI-1; i++ ) s[i] = 0;#else s[1] = 32766; s[2] = 0; for( i=M+1; i<NI-1; i++ ) s[i] = 0xffff; s[NI-1] = 0; if( (rndprc < 64) || (rndprc == 113) ) { s[rw] &= ~rmsk; if( rndprc == 24 ) { s[5] = 0; s[6] = 0; } }#endif return; }if( exp < 0 ) s[1] = 0;else s[1] = (unsigned short )exp;}/*; Subtract external format numbers.;; unsigned short a[NE], b[NE], c[NE];; esub( a, b, c ); c = b - a*/static int subflg = 0;void esub( a, b, c )unsigned short *a, *b, *c;{#ifdef NANSif( eisnan(a) ) { emov (a, c); return; }if( eisnan(b) ) { emov(b,c); return; }/* Infinity minus infinity is a NaN. * Test for subtracting infinities of the same sign. */if( eisinf(a) && eisinf(b) && ((eisneg (a) ^ eisneg (b)) == 0)) { mtherr( "esub", DOMAIN ); enan( c, NBITS ); return; }#endifsubflg = 1;eadd1( a, b, c );}/*; Add.;; unsigned short a[NE], b[NE], c[NE];; eadd( a, b, c ); c = b + a*/void eadd( a, b, c )unsigned short *a, *b, *c;{#ifdef NANS/* NaN plus anything is a NaN. */if( eisnan(a) ) { emov(a,c); return; }if( eisnan(b) ) { emov(b,c); return; }/* Infinity minus infinity is a NaN. * Test for adding infinities of opposite signs. */if( eisinf(a) && eisinf(b) && ((eisneg(a) ^ eisneg(b)) != 0) ) { mtherr( "eadd", DOMAIN ); enan( c, NBITS ); return; }#endifsubflg = 0;eadd1( a, b, c );}void eadd1( a, b, c )unsigned short *a, *b, *c;{unsigned short ai[NI], bi[NI], ci[NI];int i, lost, j, k;long lt, lta, ltb;#ifdef INFINITIESif( eisinf(a) ) { emov(a,c); if( subflg ) eneg(c); return; }if( eisinf(b) ) { emov(b,c); return; }#endifemovi( a, ai );emovi( b, bi );if( subflg ) ai[0] = ~ai[0];/* compare exponents */lta = ai[E];ltb = bi[E];lt = lta - ltb;if( lt > 0L ) { /* put the larger number in bi */ emovz( bi, ci ); emovz( ai, bi ); emovz( ci, ai ); ltb = bi[E]; lt = -lt; }lost = 0;if( lt != 0L ) { if( lt < (long )(-NBITS-1) ) goto done; /* answer same as larger addend */ k = (int )lt; lost = eshift( ai, k ); /* shift the smaller number down */ }else {/* exponents were the same, so must compare significands */ i = ecmpm( ai, bi ); if( i == 0 ) { /* the numbers are identical in magnitude */ /* if different signs, result is zero */ if( ai[0] != bi[0] ) { eclear(c); return; } /* if same sign, result is double */ /* double denomalized tiny number */ if( (bi[E] == 0) && ((bi[3] & 0x8000) == 0) ) { eshup1( bi ); goto done; } /* add 1 to exponent unless both are zero! */ for( j=1; j<NI-1; j++ ) { if( bi[j] != 0 ) { ltb += 1; if( ltb >= 0x7fff ) { eclear(c); einfin(c); if( ai[0] != 0 ) eneg(c); return; } break; } } bi[E] = (unsigned short )ltb; goto done; } if( i > 0 ) { /* put the larger number in bi */ emovz( bi, ci ); emovz( ai, bi ); emovz( ci, ai ); } }if( ai[0] == bi[0] ) { eaddm( ai, bi ); subflg = 0; }else { esubm( ai, bi ); subflg = 1; }emdnorm( bi, lost, subflg, ltb, 64 );done:emovo( bi, c );}/*; Divide.;; unsigned short a[NE], b[NE], c[NE];; ediv( a, b, c ); c = b / a*/void ediv( a, b, c )unsigned short *a, *b, *c;{unsigned short ai[NI], bi[NI];int i, sign;long lt, lta, ltb;/* IEEE says if result is not a NaN, the sign is "-" if and only if operands have opposite signs -- but flush -0 to 0 later if not IEEE. */sign = eisneg(a) ^ eisneg(b);#ifdef NANS/* Return any NaN input. */if( eisnan(a) ) { emov(a,c); return; }if( eisnan(b) ) { emov(b,c); return; }/* Zero over zero, or infinity over infinity, is a NaN. */if( ((ecmp(a,ezero) == 0) && (ecmp(b,ezero) == 0)) || (eisinf (a) && eisinf (b)) ) { mtherr( "ediv", DOMAIN ); enan( c, NBITS ); return; }#endif/* Infinity over anything else is infinity. */#ifdef INFINITIESif( eisinf(b) ) { einfin(c); goto divsign; }if( eisinf(a) ) { eclear(c); goto divsign; }#endifemovi( a, ai );emovi( b, bi );lta = ai[E];ltb = bi[E];if( bi[E] == 0 ) { /* See if numerator is zero. */ for( i=1; i<NI-1; i++ ) { if( bi[i] != 0 ) { ltb -= enormlz( bi ); goto dnzro1; } } eclear(c); goto divsign; }dnzro1:if( ai[E] == 0 ) { /* possible divide by zero */ for( i=1; i<NI-1; i++ ) { if( ai[i] != 0 ) { lta -= enormlz( ai ); goto dnzro2; } } einfin(c); mtherr( "ediv", SING ); goto divsign; }dnzro2:i = edivm( ai, bi );/* calculate exponent */lt = ltb - lta + EXONE;emdnorm( bi, i, 0, lt, 64 );emovo( bi, c );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -