/* formater for floating point numbers, called by printf and friends */ /* written by Eric R. Smith */ /* Please write something better! */ #include /* find the mantissa and exponent of a floating point number */ /* this is similar to frexp, except we want to use base 10 instead of base 2 */ /* FIXME: there has GOT to be a better way to do this. */ /* Here is a (hopefully) new improved one, ++jrb */ /* bit struct of an ieee double */ struct bitdouble { unsigned long sign : 1; unsigned long exp : 11; unsigned long mant1 : 20; unsigned long mant2; }; static double decfrexp(value, exponent) double value; int *exponent; { register struct bitdouble *p = (struct bitdouble *) &value; register unsigned short e; register short tene; tene = 0; e = p->exp; if(e > 1025) { for(; p->exp >= 1027; tene++) value /= 10.0; if((p->exp == 1026) && ( p->mant1 >= 0x40000)) { value /= 10.0; tene++; } } else if(e < 1021) { for(; p->exp <= 1022; --tene) value *= 10.0; } /* else -- need to do nothing */ *exponent = tene; return value; } /* format a floating point number */ void fp_print(value, format, precision, buf) double value; /* the number to format */ int format; /* how to format it: really a char, for now */ int precision; /* precision, or # of places after '.' */ char *buf; /* buffer into which the result goes */ { int digit; int exp; double mantissa; int decpoint = 1; int useexp = 1; int ndigits; if(precision == -1) /* ++jrb, prec not spec, use default prec */ precision = 6; if (value < 0.0) { *buf++ = '-'; value = -value; } /* ++jrb round off at prec + 1 */ for(mantissa = 0.5, ndigits = 0; ndigits < precision; ndigits++) mantissa /= 10.0; value += mantissa; mantissa = decfrexp(value, &exp); switch(format) { case 'e': case 'E': ndigits = precision + 1; /* one place in front of decimal */ break; case 'g': case 'G': default: ndigits = precision; if (exp >= -3 && exp < precision) useexp = 0; /* use f format */ break; case 'f': if (exp < 0) ndigits = precision + 1; else ndigits = precision + exp + 1; useexp = 0; break; } /* preliminaries for f format */ if (!useexp) { if (exp < 0) { *buf++ = '0'; *buf++ = '.'; ndigits--; while (++exp < 0 && ndigits > 0) { *buf++ = '0'; ndigits--; } decpoint = -1; } else { decpoint = exp + 1; } } while (ndigits > 0) { digit = (int) (mantissa); mantissa = (mantissa - (double) digit) * 10; *buf++ = digit + '0'; if (--decpoint == 0) *buf++ = '.'; --ndigits; }; if (useexp) { *buf++ = (isupper(format)) ? 'E' : 'e'; if (exp < 0) { *buf++ = '-'; exp = -exp; } else *buf++ = '+'; if((digit = exp/100) > 0) { *buf++ = digit + '0'; exp %= 100; } *buf++ = (exp/10) + '0'; *buf++ = (exp%10) + '0'; } *buf++ = '\0'; }