home *** CD-ROM | disk | FTP | other *** search
- /* formater for floating point numbers, called by printf and friends */
- /* written by Eric R. Smith */
- /* Please write something better! */
-
- #include <ctype.h>
-
- /* 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';
- }
-