diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libmath/gfltconv.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libmath/gfltconv.c')
| -rw-r--r-- | libmath/gfltconv.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libmath/gfltconv.c b/libmath/gfltconv.c new file mode 100644 index 00000000..497b71f9 --- /dev/null +++ b/libmath/gfltconv.c @@ -0,0 +1,123 @@ +#include "lib9.h" +#include "mathi.h" +extern char *dtoa(double, int, int, int *, int *, char **); +extern void freedtoa(char*); +extern int _fmtcpy(Fmt*, void*, int, int); + +enum +{ + NONE = -1000, + FDIGIT = 20, + FDEFLT = 6, + NSIGNIF = 17 +}; + +int +gfltconv(Fmt *f) +{ + int flags = f->flags; + int precision; + int fmt = f->r; + double d; + int echr, exponent, sign, ndig, nout, i; + char *digits, *edigits, ebuf[32], *eptr; + char out[64], *pout; + + d = va_arg(f->args, double); + echr = 'e'; + precision = FDEFLT; + if(f->flags & FmtPrec) + precision = f->prec; + if(precision > FDIGIT) + precision = FDIGIT; + switch(fmt){ + case 'f': + digits = dtoa(d, 3, precision, &exponent, &sign, &edigits); + break; + case 0x00c9: /* L'É' */ + case 'E': + echr = 'E'; + fmt = 'e'; + /* fall through */ + case 'e': + digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits); + break; + case 'G': + echr = 'E'; + /* fall through */ + default: + case 'g': + if((flags&(FmtWidth|FmtPrec)) == 0){ + g_fmt(out, d, echr); + f->flags &= FmtWidth|FmtLeft; + return _fmtcpy(f, out, strlen(out), strlen(out)); + } + if (precision > 0) + digits = dtoa(d, 2, precision, &exponent, &sign, &edigits); + else { + digits = dtoa(d, 0, precision, &exponent, &sign, &edigits); + precision = edigits - digits; + if (exponent > precision && exponent <= precision + 4) + precision = exponent; + } + if(exponent >= -3 && exponent <= precision){ + fmt = 'f'; + precision -= exponent; + }else{ + fmt = 'e'; + --precision; + } + break; + } + if (exponent == 9999) { + /* Infinity or Nan */ + precision = 0; + exponent = edigits - digits; + fmt = 'f'; + } + ndig = edigits-digits; + if((f->r=='g' || f->r=='G') && !(flags&FmtSharp)){ /* knock off trailing zeros */ + if(fmt == 'f'){ + if(precision+exponent > ndig) { + precision = ndig - exponent; + if(precision < 0) + precision = 0; + } + } + else{ + if(precision > ndig-1) precision = ndig-1; + } + } + eptr = ebuf; + if(fmt != 'f'){ /* exponent */ + for(i=exponent<=0?1-exponent:exponent-1; i; i/=10) + *eptr++ = '0' + i%10; + while(eptr<ebuf+2) *eptr++ = '0'; + } + pout = out; + if(sign) *pout++ = '-'; + else if(flags&FmtSign) *pout++ = '+'; + else if(flags&FmtSpace) *pout++ = ' '; + if(fmt == 'f'){ + for(i=0; i<exponent; i++) *pout++ = i<ndig?digits[i]:'0'; + if(i == 0) *pout++ = '0'; + if(precision>0 || flags&FmtSharp) *pout++ = '.'; + for(i=0; i!=precision; i++) + *pout++ = 0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0'; + } + else{ + *pout++ = digits[0]; + if(precision>0 || flags&FmtSharp) *pout++ = '.'; + for(i=0; i!=precision; i++) *pout++ = i<ndig-1?digits[i+1]:'0'; + } + if(fmt != 'f'){ + *pout++ = echr; + *pout++ = exponent<=0?'-':'+'; + while(eptr>ebuf) *pout++ = *--eptr; + } + *pout = 0; + freedtoa(digits); + f->flags &= FmtWidth|FmtLeft; + nout = pout-out; + return _fmtcpy(f, out, nout, nout); +} |
