diff options
Diffstat (limited to 'libc/i386fp')
-rw-r--r-- | libc/i386fp/Makefile | 4 | ||||
-rw-r--r-- | libc/i386fp/ecvt.c | 122 |
2 files changed, 124 insertions, 2 deletions
diff --git a/libc/i386fp/Makefile b/libc/i386fp/Makefile index 298ca18..e26ce21 100644 --- a/libc/i386fp/Makefile +++ b/libc/i386fp/Makefile @@ -9,12 +9,12 @@ FPSRC =fadd.x fcomp.x fdiv.x fmul.x fbsr.x \ fperr.c fperror.x fptoi.x fpushd.x fpulld.x \ fpushi.x fpushf.x fpullf.x frexp.x ftst.x \ gcclib.x \ - fabs.x ldexp.x modf.c \ + fabs.x ldexp.x ecvt.c \ fperr.h fplib.h FPOBJ =fadd.o fcomp.o fdiv.o fmul.o fpbsr.o \ fperr.o fperror.o fptoi.o fpushd.o fpulld.o \ fpushi.o fpushf.o fpullf.o frexp.o ftst.o \ - fabs.o ldexp.o modf.o + fabs.o ldexp.o ecvt.o LIB =. CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS) diff --git a/libc/i386fp/ecvt.c b/libc/i386fp/ecvt.c new file mode 100644 index 0000000..6e0cef1 --- /dev/null +++ b/libc/i386fp/ecvt.c @@ -0,0 +1,122 @@ + +#define DIGMAX 30 /* max # of digits in string */ +#define DIGPREC 17 /* max # of significant digits */ +#define ECVT 0 +#define FCVT 1 +static char digstr[DIGMAX + 1 + 1]; /* +1 for end of string */ + + /* +1 in case rounding adds */ + /* another digit */ +static double negtab[] = + { 1e-256, 1e-128, 1e-64, 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1, 1.0 }; +static double postab[] = + { 1e+256, 1e+128, 1e+64, 1e+32, 1e+16, 1e+8, 1e+4, 1e+2, 1e+1 }; + +static char *_cvt(); + +/************************* + * Convert double val to a string of + * decimal digits. + * ndig = # of digits in resulting string + * Returns: + * *pdecpt = position of decimal point from left of first digit + * *psign = nonzero if value was negative + */ +char * +ecvt(val, ndig, pdecpt, psign) +double val; +int ndig, *pdecpt, *psign; + +{ + return _cvt(ECVT, val, ndig, pdecpt, psign); +} + +char * +fcvt(val, nfrac, pdecpt, psign) +double val; +int nfrac, *pdecpt, *psign; + +{ + return _cvt(FCVT, val, nfrac, pdecpt, psign); +} + +static char * +_cvt(cnvflag, val, ndig, pdecpt, psign) +double val; +int ndig, *pdecpt, *psign; + +{ + int decpt, pow, i; + char *p; + *psign = (val < 0) ? ((val = -val), 1) : 0; + ndig = (ndig < 0) ? 0 : (ndig < DIGMAX) ? ndig : DIGMAX; + if (val == 0) { + for (p = &digstr[0]; p < &digstr[ndig]; p++) + *p = '0'; + decpt = 0; + } else { + /* Adjust things so that 1 <= val < 10 */ + /* in these loops if val == MAXDOUBLE) */ + decpt = 1; + pow = 256; + i = 0; + while (val < 1) { + while (val < negtab[i + 1]) { + val /= negtab[i]; + decpt -= pow; + } + pow >>= 1; + i++; + } + pow = 256; + i = 0; + while (val >= 10) { + while (val >= postab[i]) { + val /= postab[i]; + decpt += pow; + } + pow >>= 1; + i++; + } + if (cnvflag == FCVT) { + ndig += decpt; + ndig = (ndig < 0) ? 0 : (ndig < DIGMAX) ? ndig : DIGMAX; + } + + /* Pick off digits 1 by 1 and stuff into digstr[] */ + /* Do 1 extra digit for rounding purposes */ + for (p = &digstr[0]; p <= &digstr[ndig]; p++) { + int n; + + /* 'twould be silly to have zillions of digits */ + /* when only DIGPREC are significant */ + if (p >= &digstr[DIGPREC]) + *p = '0'; + + else { + n = val; + *p = n + '0'; + val = (val - n) * 10; /* get next digit */ + } + } + if (*--p >= '5') { /* if we need to round */ + while (1) { + if (p == &digstr[0]) { /* if at start */ + ndig += cnvflag; + decpt++; /* shift dec pnt */ + digstr[0] = '1'; /* "100000..." */ + break; + } + *p = '0'; + --p; + if (*p != '9') { + (*p)++; + break; + } + } /* while */ + } /* if */ + } /* else */ + *pdecpt = decpt; + digstr[ndig] = 0; /* terminate string */ + return &digstr[0]; +} |