📄 ieee.c
字号:
p = &equot[0];
*p++ = num[0];
*p++ = num[1];
for( i=M; i<NI; i++ )
{
*p++ = 0;
}
/* Use faster compare and subtraction if denominator
* has only 15 bits of significance.
*/
p = &den[M+2];
if( *p++ == 0 )
{
for( i=M+3; i<NI; i++ )
{
if( *p++ != 0 )
goto fulldiv;
}
if( (den[M+1] & 1) != 0 )
goto fulldiv;
eshdn1(num);
eshdn1(den);
p = &den[M+1];
q = &num[M+1];
for( i=0; i<NBITS+2; i++ )
{
if( *p <= *q )
{
*q -= *p;
j = 1;
}
else
{
j = 0;
}
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 b
by 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 denominator
is 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 INFINITY
if( j > NBITS )
{
ecleazs( s );
return;
}
#endif
exp -= j;
#ifndef INFINITY
if( exp >= 32767L )
goto overf;
#else
if( (j > NBITS) && (exp < 32767L) )
{
ecleazs( s );
return;
}
#endif
if( 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.
*/
#if IBMPC
if( (exp <= 0) && (rndprc != NBITS) )
#else
if( (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:
#if IBMPC
if( (exp <= 0) && (rndprc != NBITS) )
#else
if( (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 INFINITY
overf:
#endif
#ifdef INFINITY
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 NANS
if( 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;
}
#endif
subflg = 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;
}
#endif
subflg = 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 INFINITY
if( eisinf(a) )
{
emov(a,c);
if( subflg )
eneg(c);
return;
}
if( eisinf(b) )
{
emov(b,c);
return;
}
#endif
emovi( 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 )
{
/* This could overflow, but let emovo take care of that. */
ltb += 1;
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;
long lt, lta, ltb;
#ifdef NANS
/* Return any NaN input. */
if( eisnan(a) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -