home *** CD-ROM | disk | FTP | other *** search
- /*
- * double modf(value, iptr)
- * double value;
- * double *iptr;
- *
- * returns fractional part of value
- * in *iptr returns the integral part
- * such that (*iptr + fractional) == value
- *
- * ++jrb bammi@dsrgsun.ces.cwru.edu
- *
- * special thanks to peter housel housel@ecn.purdue.edu
- * this (improved) version is based on his X86 code
- *
- */
- #include "flonum.h"
-
- #define BIAS 1023
- #define B1 1022 /* BIAS - 1 */
- #define B2 1075 /* (BIAS - 1) + 53 == max bias for integ part */
- #define B3 1011 /* (BIAS - 1) - 11 == the max bias for a frac. # */
-
- struct ldouble {
- unsigned long hi, lo;
- }; /* another alias for double */
-
- double modf(value, iptr)
- double value, *iptr;
- {
- struct bitdouble *bd = (struct bitdouble *)&value;
- unsigned int expo = bd->exp;
- #ifdef __STDC__
- double norm( double, int, int, int );
- #else
- extern double norm();
- #endif
-
- if(expo <= B1) /* all frac, no integ */
- {
- *iptr = 0.0;
- return value;
- }
- if(expo >= B2) /* all integ, no frac */
- {
- *iptr = value;
- return 0.0;
- }
-
- /* both integ and frac */
- {
- register unsigned long i0, i1; /* integral part accumulator */
- register unsigned long f0, f1; /* fractional part accumulator */
- unsigned int sign = bd->sign;
-
- i0 = bd->mant1 | 0x00100000L;
- i1 = bd->mant2;
- f0 = f1 = 0L;
-
- do
- {
- /* shift R integ/frac, with bit falling into frac acc */
- asm volatile(" lsrl #1,%1;
- roxrl #1,%0"
- : "=d" (i1), "=d" (i0)
- : "0" (i1), "1" (i0) );
-
- asm volatile(" roxrl #1,%1;
- roxrl #1,%0"
- : "=d" (f1), "=d" (f0)
- : "0" (f1), "1" (f0) );
-
- } while(++expo < B2);
-
- /* stuff the results, and normalize */
- ((struct ldouble *)&value)->hi = i0; /* integral part */
- ((struct ldouble *)&value)->lo = i1;
- *iptr = norm(value, expo, sign, 0);
-
- /* dont call norm if frac is all zero, as B3 exp will screw it up */
- if((f0 == 0) && (f1 == 0))
- return 0.0;
-
- ((struct ldouble *)&value)->hi = f0; /* fractional part */
- ((struct ldouble *)&value)->lo = f1;
- return norm(value, B3, sign, 0);
- }
- }
-
-
- #ifdef TEST
- #include <stdio.h>
- #ifdef __MSHORT__
- #error "please run this test in 32 bit int mode"
- #endif
-
- #define NTEST 100000L
- #define MAXRAND 0x7fffffffL /* assuming 32 bit ints */
- #define ABS(X) ( (X < 0) ? (-X) : X )
- extern long rand();
-
- int main()
- {
- double frac, integ, e, expected, result, max_abs_err;
- register long i;
- register long errs = 0;
- register int s;
-
- max_abs_err = 0.0;
- for(i = 0; i < NTEST; i++)
- {
- expected = ((double)(s = rand()) + (double)rand())/(double)(MAXRAND);
- if(s > (MAXRAND >> 1)) expected = -expected;
- frac = modf(expected, &integ);
- if(ABS(frac) >= 1.0)
- {
- printf("|frac| >= 1, %.6e: integ %.6e frac %.6e\n",
- expected, integ, frac);
- errs++;
- continue;
- }
- if( (integ != 0) && (ABS(integ) < 1.0) )
- {
- printf("|integ| < 1, %.6e: integ %.6e frac %.6e\n",
- expected, integ, frac);
- errs++;
- continue;
- }
-
- result = integ + frac;
- e = (expected == 0.0) ? result : (result - expected)/expected;
- if(e < 0) e = (-e);
- if(e > 1.0e-6)
- {
- printf("%.4e: I %.4e F %.4e R %.4e E %.8e\n",
- expected, integ, frac, result, e);
- errs++;
- }
- if (e > max_abs_err) max_abs_err = e;
- }
-
- printf("%ld Error(s), Max abs err %.14e\n", errs, max_abs_err);
- return errs;
- }
- #endif /* TEST */
-