emfloat.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,275 行 · 第 1/3 页
C
1,275 行
/*
** Set the sticky bit if any bits set in extra bits.
*/
if (IsMantissaZero(extra_bits))
{
z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
}
break;
case NAN_NAN:
choose_nan(x, y, z, 0);
break;
}
/*
** All math done...do rounding.
*/
RoundInternalFPF(z);
return;
}
/**********************
** DivideInternalFPF **
***********************
** Divide internal FPF number x by y. Return result in z.
*/
static void DivideInternalFPF(InternalFPF *x,
InternalFPF *y,
InternalFPF *z)
{
int i;
int j;
u16 carry;
u16 extra_bits[INTERNAL_FPF_PRECISION];
InternalFPF locx; /* Local for x number */
/*
** As with preceding function, the following switch
** statement selects among the various possible
** operands.
*/
switch ((x->type * IFPF_TYPE_COUNT) + y->type)
{
case ZERO_ZERO:
case INFINITY_INFINITY:
SetInternalFPFNaN(z);
break;
case ZERO_SUBNORMAL:
case ZERO_NORMAL:
if (IsMantissaZero(y->mantissa))
{
SetInternalFPFNaN(z);
break;
}
case ZERO_INFINITY:
case SUBNORMAL_INFINITY:
case NORMAL_INFINITY:
SetInternalFPFZero(z, x->sign ^ y->sign);
break;
case SUBNORMAL_ZERO:
case NORMAL_ZERO:
if (IsMantissaZero(x->mantissa))
{
SetInternalFPFNaN(z);
break;
}
case INFINITY_ZERO:
case INFINITY_SUBNORMAL:
case INFINITY_NORMAL:
SetInternalFPFInfinity(z, 0);
z->sign = x->sign ^ y->sign;
break;
case NAN_ZERO:
case NAN_SUBNORMAL:
case NAN_NORMAL:
case NAN_INFINITY:
memmove((void *)x,(void *)z,sizeof(InternalFPF));
break;
case ZERO_NAN:
case SUBNORMAL_NAN:
case NORMAL_NAN:
case INFINITY_NAN:
memmove((void *)y,(void *)z,sizeof(InternalFPF));
break;
case SUBNORMAL_SUBNORMAL:
case NORMAL_SUBNORMAL:
case SUBNORMAL_NORMAL:
case NORMAL_NORMAL:
/*
** Make local copy of x number, since we'll be
** altering it in the process of dividing.
*/
memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
/*
** Check for unnormal zero arguments
*/
if (IsMantissaZero(locx.mantissa))
{
if (IsMantissaZero(y->mantissa))
SetInternalFPFNaN(z);
else
SetInternalFPFZero(z, 0);
break;
}
if (IsMantissaZero(y->mantissa))
{
SetInternalFPFInfinity(z, 0);
break;
}
/*
** Initialize the result
*/
z->type = x->type;
z->sign = x->sign ^ y->sign;
z->exp = x->exp - y->exp +
((INTERNAL_FPF_PRECISION * 16 * 2));
for (i=0; i<INTERNAL_FPF_PRECISION; i++)
{
z->mantissa[i] = 0;
extra_bits[i] = 0;
}
while ((z->mantissa[0] & 0x8000) == 0)
{
carry = 0;
ShiftMantLeft1(&carry, locx.mantissa);
ShiftMantLeft1(&carry, extra_bits);
/*
** Time to subtract yet?
*/
if (carry == 0)
for (j=0; j<INTERNAL_FPF_PRECISION; j++)
{
if (y->mantissa[j] > extra_bits[j])
{
carry = 0;
goto no_subtract;
}
if (y->mantissa[j] < extra_bits[j])
break;
}
/*
** Divisor (y) <= dividend (x), subtract
*/
carry = 0;
for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
Sub16Bits(&carry,
&extra_bits[j],
extra_bits[j],
y->mantissa[j]);
carry = 1; /* 1 shifted into quotient */
no_subtract:
ShiftMantLeft1(&carry, z->mantissa);
z->exp--;
}
break;
case NAN_NAN:
choose_nan(x, y, z, 0);
break;
}
/*
** Math complete...do rounding
*/
RoundInternalFPF(z);
}
/**********************
** LongToInternalFPF **
***********************
** Convert a signed long integer into an internal FPF number.
*/
static void LongToInternalFPF(long mylong,
InternalFPF *dest)
{
int i; /* Index */
u16 myword; /* Used to hold converted stuff */
/*
** Save the sign and get the absolute value. This will help us
** with 64-bit machines, since we use only the lower 32
** bits just in case.
*/
if(mylong<0L)
{ dest->sign=1;
mylong=0L-mylong;
}
else
dest->sign=0;
/*
** Prepare the destination floating point number
*/
dest->type=IFPF_IS_NORMAL;
for(i=0;i<INTERNAL_FPF_PRECISION;i++)
dest->mantissa[i]=0;
/*
** See if we've got a zero. If so, make the resultant FP
** number a true zero and go home.
*/
if(mylong==0)
{ dest->type=IFPF_IS_ZERO;
dest->exp=0;
return;
}
/*
** Not a true zero. Set the exponent to 32 (internal FPFs have
** no bias) and load the low and high words into their proper
** locations in the mantissa. Then normalize. The action of
** normalizing slides the mantissa bits into place and sets
** up the exponent properly.
*/
dest->exp=32;
myword=(u16)((mylong >> 16) & 0xFFFFL);
dest->mantissa[0]=myword;
myword=(u16)(mylong & 0xFFFFL);
dest->mantissa[1]=myword;
normalize(dest);
return;
}
#if 0
/************************
** InternalFPFToString **
*************************
** FOR DEBUG PURPOSES
** This routine converts an internal floating point representation
** number to a string. Used in debugging the package.
** Returns length of converted number.
** NOTE: dest must point to a buffer big enough to hold the
** result. Also, this routine does append a null (an effect
** of using the sprintf() function). It also returns
** a length count.
** NOTE: This routine returns 5 significant digits. Thats
** about all I feel safe with, given the method of
** conversion. It should be more than enough for programmers
** to determine whether the package is properly ported.
*/
static int InternalFPFToString(char *dest,
InternalFPF *src)
{
InternalFPF locFPFNum; /* Local for src (will be altered) */
InternalFPF IFPF10; /* Floating-point 10 */
InternalFPF IFPFComp; /* For doing comparisons */
int msign; /* Holding for mantissa sign */
int expcount; /* Exponent counter */
int ccount; /* Character counter */
int i,j,k; /* Index */
u16 carryaccum; /* Carry accumulator */
u16 mycarry; /* Local for carry */
/*
** Check first for the simple things...Nan, Infinity, Zero.
** If found, copy the proper string in and go home.
*/
switch(src->type)
{
case IFPF_IS_NAN:
memcpy(dest,"NaN",3);
return(3);
case IFPF_IS_INFINITY:
if(src->sign==0)
memcpy(dest,"+Inf",4);
else
memcpy(dest,"-Inf",4);
return(4);
case IFPF_IS_ZERO:
if(src->sign==0)
memcpy(dest,"+0",2);
else
memcpy(dest,"-0",2);
return(2);
}
/*
** Move the internal number into our local holding area, since
** we'll be altering it to print it out.
*/
memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF));
/*
** Set up a floating-point 10...which we'll use a lot in a minute.
*/
LongToInternalFPF(10L,&IFPF10);
/*
** Save the mantissa sign and make it positive.
*/
msign=src->sign;
src->sign=0;
expcount=0; /* Init exponent counter */
/*
** See if the number is less than 10. If so, multiply
** the number repeatedly by 10 until it's not. For each
** multiplication, decrement a counter so we can keep track
** of the exponent.
*/
while(1)
{ AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
if(IFPFComp.sign==0) break;
MultiplyInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
expcount--;
memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
}
/*
** Do the reverse of the above. As long as the number is
** greater than or equal to 10, divide it by 10. Increment the
** exponent counter for each multiplication.
*/
while(1)
{
AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
if(IFPFComp.sign!=0) break;
DivideInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
expcount++;
memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
}
/*
** About time to start storing things. First, store the
** mantissa sign.
*/
ccount=1; /* Init character counter */
if(msign==0)
*dest++='+';
else
*dest++='-';
/*
** At this point we know that the number is in the range
** 10 > n >=1. We need to "strip digits" out of the
** mantissa. We do this by treating the mantissa as
** an integer and multiplying by 10. (Not a floating-point
** 10, but an integer 10. Since this is debug code and we
** could care less about speed, we'll do it the stupid
** way and simply add the number to itself 10 times.
** Anything that makes it to the left of the implied binary point
** gets stripped off and emitted. We'll do this for
** 5 significant digits (which should be enough to
** verify things).
*/
/*
** Re-position radix point
*/
carryaccum=0;
while(locFPFNum.exp>0)
{
mycarry=0;
ShiftMantLeft1(&mycarry,locFPFNum.mantissa);
carryaccum=(carryaccum<<1);
if(mycarry) carryaccum++;
locFPFNum.exp--;
}
while(locFPFNum.exp<0)
{
mycarry=0;
ShiftMantRight1(&mycarry,locFPFNum.mantissa);
locFPFNum.exp++;
}
for(i=0;i<6;i++)
if(i==1)
{ /* Emit decimal point */
*dest++='.';
ccount++;
}
else
{ /* Emit a digit */
*dest++=('0'+carryaccum);
ccount++;
carryaccum=0;
memcpy((void *)&IFPF10,
(void *)&locFPFNum,
sizeof(InternalFPF));
/* Do multiply via repeated adds */
for(j=0;j<9;j++)
{
mycarry=0;
for(k=(INTERNAL_FPF_PRECISION-1);k>=0;k--)
Add16Bits(&mycarry,&(IFPFComp.mantissa[k]),
locFPFNum.mantissa[k],
IFPF10.mantissa[k]);
carryaccum+=mycarry ? 1 : 0;
memcpy((void *)&locFPFNum,
(void *)&IFPFComp,
sizeof(InternalFPF));
}
}
/*
** Now move the 'E', the exponent sign, and the exponent
** into the string.
*/
*dest++='E';
ccount+=sprintf(dest,"%4d",expcount);
/*
** All done, go home.
*/
return(ccount);
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?