📄 ieee.c
字号:
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.
*/
#ifdef 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:
#ifdef 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 )
{
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 INFINITY
if( eisinf(b) )
{
einfin(c);
goto divsign;
}
if( eisinf(a) )
{
eclear(c);
goto divsign;
}
#endif
emovi( 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 );
divsign:
if( sign )
*(c+(NE-1)) |= 0x8000;
else
*(c+(NE-1)) &= ~0x8000;
}
/*
; Multiply.
;
; unsigned short a[NE], b[NE], c[NE];
; emul( a, b, c ); c = b * a
*/
void emul( a, b, c )
unsigned short *a, *b, *c;
{
unsigned short ai[NI], bi[NI];
int i, j, 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
/* NaN times anything is the same NaN. */
if( eisnan(a) )
{
emov(a,c);
return;
}
if( eisnan(b) )
{
emov(b,c);
return;
}
/* Zero times infinity is a NaN. */
if( (eisinf(a) && (ecmp(b,ezero) == 0))
|| (eisinf(b) && (ecmp(a,ezero) == 0)) )
{
mtherr( "emul", DOMAIN );
enan( c, NBITS );
return;
}
#endif
/* Infinity times anything else is infinity. */
#ifdef INFINITY
if( eisinf(a) || eisinf(b) )
{
einfin(c);
goto mulsign;
}
#endif
emovi( a, ai );
emovi( b, bi );
lta = ai[E];
ltb = bi[E];
if( ai[E] == 0 )
{
for( i=1; i<NI-1; i++ )
{
if( ai[i] != 0 )
{
lta -= enormlz( ai );
goto mnzer1;
}
}
eclear(c);
goto mulsign;
}
mnzer1:
if( bi[E] == 0 )
{
for( i=1; i<NI-1; i++ )
{
if( bi[i] != 0 )
{
ltb -= enormlz( bi );
goto mnzer2;
}
}
eclear(c);
goto mulsign;
}
mnzer2:
/* Multiply significands */
j = emulm( ai, bi );
/* calculate exponent */
lt = lta + ltb - (EXONE - 1);
emdnorm( bi, j, 0, lt, 64 );
emovo( bi, c );
/* IEEE says sign is "-" if and only if operands have opposite signs. */
mulsign:
if( sign )
*(c+(NE-1)) |= 0x8000;
else
*(c+(NE-1)) &= ~0x8000;
}
/*
; Convert IEEE double precision to e type
; double d;
; unsigned short x[N+2];
; e53toe( &d, x );
*/
void e53toe( pe, y )
unsigned short *pe, *y;
{
#ifdef DEC
dectoe( pe, y ); /* see etodec.c */
#else
register unsigned short r;
register unsigned short *p, *e;
unsigned short yy[NI];
int denorm, k;
e = pe;
denorm = 0; /* flag if denormalized number */
ecleaz(yy);
#ifdef IBMPC
e += 3;
#endif
r = *e;
yy[0] = 0;
if( r & 0x8000 )
yy[0] = 0xffff;
yy[M] = (r & 0x0f) | 0x10;
r &= ~0x800f; /* strip sign and 4 significand bits */
#ifdef INFINITY
if( r == 0x7ff0 )
{
#ifdef NANS
#ifdef IBMPC
if( ((pe[3] & 0xf) != 0) || (pe[2] != 0)
|| (pe[1] != 0) || (pe[0] != 0) )
{
enan( y, NBITS );
return;
}
#else
if( ((pe[0] & 0xf) != 0) || (pe[1] != 0)
|| (pe[2] != 0) || (pe[3] != 0) )
{
enan( y, NBITS );
return;
}
#endif
#endif /* NANS */
eclear( y );
einfin( y );
if( yy[0] )
eneg(y);
return;
}
#endif
r >>= 4;
/* If zero exponent, then the significand is denormalized.
* So, take back the understood high significand bit. */
if( r == 0 )
{
denorm = 1;
yy[M] &= ~0x10;
}
r += EXONE - 01777;
yy[E] = r;
p = &yy[M+1];
#ifdef IBMPC
*p++ = *(--e);
*p++ = *(--e);
*p++ = *(--e);
#endif
#ifdef MIEEE
++e;
*p++ = *e++;
*p++ = *e++;
*p++ = *e++;
#endif
(void )eshift( yy, -5 );
if( denorm )
{ /* if zero exponent, then normalize the significand */
if( (k = enormlz(yy)) > NBITS )
ecleazs(yy);
else
yy[E] -= (unsigned short )(k-1);
}
emovo( yy, y );
#endif /* not DEC */
}
void e64toe( pe, y )
unsigned short *pe, *y;
{
unsigned short yy[NI];
unsigned short *p, *q, *e;
int i;
e = pe;
p = yy;
for( i=0; i<NE-5; i++ )
*p++ = 0;
#ifdef IBMPC
for( i=0; i<5; i++ )
*p++ = *e++;
#endif
#ifdef DEC
for( i=0; i<5; i++ )
*p++ = *e++;
#endif
#ifdef MIEEE
p = &yy[0] + (NE-1);
*p-- = *e++;
++e;
for( i=0; i<4; i++ )
*p-- = *e++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -