home *** CD-ROM | disk | FTP | other *** search
- /*
- * Ieee double normalization function
- *
- * double norm( double d, int exp, int sign, int rbits )
- *
- * inputs:
- * m a 63 bit mantissa (passed as 8 bytes in a double's storage)
- * exp BIASED exponent
- * sign sign of the result (1 == -ve 0 == +ve)
- * rbits 8 bits of rounding info
- * on input radix point is at extreme right (exp should reflect this)
- * output:
- * the normalized double in ieee double format
- *
- * algorithm:
- * see posting by p. housel housel@ecn.purdue.edu (thanks peter)
- * and knuth v2 section 4.2.1 algorithm N
- *
- * ++jrb bammi@dsrgsun.ces.cwru.edu
- * bugs:
- * strictly mc68X coding
- * (can be coded using gnu c `long long' type very easily)
- */
- #include "flonum.h"
-
- struct ldouble {
- unsigned long hi, lo;
- }; /* yet another alias for a double */
-
- double norm( double m, int exp, int sign, int rbits )
- {
- /* we'll use constraints later for values to end up in D reggies */
- register unsigned long d0, d1; /* 64 bit accumulator */
- register char rounding; /* rounding reg-signed char for convenience */
- double result; /* the normalized result */
- struct bitdouble *r = (struct bitdouble *)&result; /* alias */
-
- /* init */
- d0 = ((struct ldouble *)&m)->hi;
- d1 = ((struct ldouble *)&m)->lo;
- rounding = rbits;
-
- if( (d0 == 0) && (d1 == 0) && (rounding == 0) )
- goto stuff_result; /* nothing to do, but stuff bits into result */
-
- /* keep shifting R & accumulating rounding bits until we have 53 bits */
- /* lsb of rounding register is sticky for 1 bits shifted out */
-
- asm volatile("ReNormalize:"); /* ok, i admit it :-) */
- while( (d0 & 0xffe00000L) != 0)
- {
- #if 0 /* only 5 operands allowed in asm() - why?? */
- asm volatile (" lsrl #1,%2 ;
- roxrl #1,%1 ;
- roxrb #1,%0 ;
- jcc NoCarry;
- orb #1,%0 ;
- NoCarry: "
- : "=d" (rounding), "=d" (d1), "=d" (d0) /* outputs */
- : "0" (rounding), "1" (d1), "2" (d0) ); /* inputs */
- #else
- asm volatile (" lsrl #1,%1 ;
- roxrl #1,%0 "
- : "=d" (d1), "=d" (d0) /* outputs */
- : "0" (d1), "1" (d0) ); /* inputs */
- asm volatile (" roxrb #1,%0 ;
- jcc NoCarry;
- orb #1,%0 ;
- NoCarry: "
- : "=d" (rounding) /* outputs */
- : "0" (rounding) ); /* inputs */
- #endif
- /* increment exponent to reflect the shift */
- exp++;
- }
-
- /* shift L until there is a 1 in the hidden bit pos, shifting
- the rounding reggie into the lsb */
- while( (d0 & 0x00100000L) == 0)
- {
- #if 0 /* same here */
- asm volatile (" lslb #1,%2 ;
- roxll #1,%1 ;
- roxll #1,%0 "
- : "=d" (d0), "=d" (d1), "=d" (rounding) /* outputs */
- : "0" (d0), "1" (d1), "2" (rounding) ); /* inputs */
- #else
- asm volatile (" lslb #1,%1 ;
- roxll #1,%0 "
- : "=d" (d1), "=d" (rounding) /* outputs */
- : "0" (d1), "1" (rounding) ); /* inputs */
-
- asm volatile (" roxll #1,%0 "
- : "=d" (d0) /* outputs */
- : "0" (d0)); /* inputs */
- #endif
- /* decrement exponent to reflect the shift */
- --exp;
- }
-
- /* check rounding register */
- if (rounding < 0)
- { /* not round down */
- if( (((unsigned char)rounding) & 0x80) == 0)
- { /* tie: round to even */
- d1 &= 0xfffffffeL; /* set lsb to 0 */
- }
- else
- { /* round up */
- rounding = 0;
- asm volatile ("
- addql #1,%1 ;
- jcc NoCarry1 ;
- addql #1,%0 ;
- bra ReNormalize; |just in case of overflow into hidden bit\n
- NoCarry1: "
- : "=d" (d0), "=d" (d1) /* outputs */
- : "0" (d0), "1" (d1) ); /* inputs */
- }
- }
-
- /* exponent underflow ?? */
- if(exp <= 0)
- {
- printf("Underflow %lx %lx %d\n", d0, d1, exp);
- d0 = 0;
- d1 = 0;
- sign = 0;
- exp = 0;
- goto stuff_result;
- }
- /* exp overflow ? */
- if(exp >= 2047)
- {
- /* cause overflow trap, but how ?? */
- printf("Overflow %lx %lx %d\n", d0, d1, exp);
- }
-
- stuff_result: /* stuff bit in result and ret */
- r->sign = sign;
- r->exp = exp;
- r->mant1 = d0;
- r->mant2 = d1;
-
- return result;
- }
-
- #ifdef TEST
- #ifdef __MSHORT__
- #error "please run this test in 32 bit int mode"
- #endif
-
- #include <stdio.h>
-
- main()
- {
- register unsigned long d0, d1;
- double r1, r2, r3;
- struct bitdouble *pr1 = (struct bitdouble *)&r1;
- struct bitdouble *pr3 = (struct bitdouble *)&r3;
- unsigned long *l = (unsigned long *)&r2;
-
- r2 = r1 = 3.14159265358979323846265e23;
-
- *l &= 0x000FFFFFL; /* wallup sign and exponent in r2 */
- *l |= 0x00100000L; /* add hidden bit */
-
- /* try the straight case first */
- r3 = norm(r2, (unsigned int)pr1->exp, (unsigned int)pr1->sign, 0);
-
- printf("%30.25e %05lx %08lx %4d %1d\n", r1, pr1->mant1, pr1->mant2,
- pr1->exp, pr1->sign);
- printf("%30.25e %05lx %08lx %4d %1d\n\n", r3, pr3->mant1, pr3->mant2,
- pr3->exp, pr3->sign);
-
- /* shift L and try */
- d0 = l[0];
- d1 = l[1];
- asm volatile (" lsll #1,%1 ;
- roxll #1,%0 "
- : "=d" (d0), "=d" (d1) /* outputs */
- : "0" (d0), "1" (d1) ); /* inputs */
- l[0] = d0;
- l[1] = d1;
-
- r3 = norm(r2, (unsigned int)pr1->exp - 1, (unsigned int)pr1->sign, 0);
-
- printf("%30.25e %05lx %08lx %4d %1d\n", r1, pr1->mant1, pr1->mant2,
- pr1->exp, pr1->sign);
- printf("%30.25e %05lx %08lx %4d %1d\n\n", r3, pr3->mant1, pr3->mant2,
- pr3->exp, pr3->sign);
-
- /* how about a shift R */
- r2 =r1;
-
- *l &= 0x000FFFFFL; /* wallup sign and exponent in r2 */
- *l |= 0x00100000L; /* add hidden bit */
-
- d0 = l[0];
- d1 = l[1];
- asm volatile (" lsrl #1,%0 ;
- roxrl #1,%1 "
- : "=d" (d0), "=d" (d1) /* outputs */
- : "0" (d0), "1" (d1) ); /* inputs */
- l[0] = d0;
- l[1] = d1;
-
- r3 = norm(r2, (unsigned int)pr1->exp + 1, (unsigned int)pr1->sign, 0);
-
- printf("%30.25e %05lx %08lx %4d %1d\n", r1, pr1->mant1, pr1->mant2,
- pr1->exp, pr1->sign);
- printf("%30.25e %05lx %08lx %4d %1d\n\n", r3, pr3->mant1, pr3->mant2,
- pr3->exp, pr3->sign);
- }
- #endif
-