|
|
1.1 ! root 1: /* ! 2: * Floating point output conversion routines for 'printf'. ! 3: * Conditionalized #if NDP to do 8087 conversion. ! 4: */ ! 5: ! 6: #include <math.h> ! 7: ! 8: extern char *_dtoa(); ! 9: extern char *_dtof(); ! 10: extern double frexp(); ! 11: extern double modf(); ! 12: extern double _pow10(); ! 13: ! 14: #if NDP ! 15: #include <stdio.h> ! 16: ! 17: extern char *strcpy(); ! 18: ! 19: /* ! 20: * This table is indexed by the return value of the "_fxam" routine. ! 21: * The number is converted if the entry is NULL, ! 22: * otherwise the entry gives the string to print. ! 23: */ ! 24: static readonly char *fxamsg[] = { ! 25: "{+ Unnormal}", ! 26: "{+ NAN}", ! 27: "{- Unnormal}", ! 28: "{- NAN}", ! 29: NULL, /* + Normal */ ! 30: "{+ Infinity}", ! 31: NULL, /* - Normal */ ! 32: "{- Infinity}", ! 33: NULL, /* +0 */ ! 34: NULL, /* Empty */ ! 35: NULL, /* -0 */ ! 36: NULL, /* Empty */ ! 37: "{+ Denormal}", ! 38: NULL, /* Empty */ ! 39: "{- Denormal}", ! 40: NULL /* Empty */ ! 41: }; ! 42: #endif ! 43: ! 44: /* ! 45: * Convert a floating point number 'd' from binary ! 46: * into 'e', 'f' or 'g' format ASCII in the buffer 'buf'. ! 47: * The 'fmt' argument is the conversion type. ! 48: * The 'prec' argument is the precision. ! 49: * Return a pointer past the last character. ! 50: */ ! 51: char * ! 52: _dtefg(fmt, dp, prec, buf) ! 53: int fmt; ! 54: double *dp; ! 55: int prec; ! 56: register char *buf; ! 57: { ! 58: register char *cp; ! 59: int decexp, sign; ! 60: char tbuf[64]; ! 61: double d; ! 62: ! 63: d = *dp; ! 64: #if NDP ! 65: /* Print given string if 8087 format is special. */ ! 66: if ((cp=fxamsg[_fxam(d)]) != NULL) { ! 67: strcpy(buf, cp); ! 68: return(buf + strlen(buf)); ! 69: } ! 70: #endif ! 71: ! 72: if (prec < 0) ! 73: prec = 6; /* Default precision */ ! 74: if (d < 0.0) { ! 75: d = -d; /* Force d nonnegative */ ! 76: *buf++ = '-'; /* Leading '-' */ ! 77: } ! 78: cp = _dtoa(fmt, d, prec, &decexp, &sign, tbuf); ! 79: if (fmt == 'e' ! 80: || (fmt == 'g' && (decexp > 4 || decexp < -prec))) { /* 'e' format */ ! 81: buf = _dtof(buf, cp, prec, 0, fmt=='g'); /* mantissa */ ! 82: if (decexp >= 0) ! 83: sprintf(buf, "e+%02u", decexp); /* exponent */ ! 84: else ! 85: sprintf(buf, "e-%02u", -decexp); ! 86: return(buf + strlen(buf)); ! 87: } ! 88: return(_dtof(buf, cp, prec, decexp, fmt=='g')); /* 'f' format */ ! 89: } ! 90: ! 91: /* ! 92: * Copy ASCII number from 'cp' to 'buf' in %f format ! 93: * with precision 'prec' and decimal exponent 'decexp'. ! 94: * The 'isgfmt' flag determines whether trailing zeros are suppressed. ! 95: * Return a pointer past the last character. ! 96: */ ! 97: static ! 98: char * ! 99: _dtof(buf, cp, prec, decexp, isgfmt) ! 100: register char *buf; ! 101: register char *cp; ! 102: register int prec; ! 103: register int decexp; ! 104: int isgfmt; ! 105: { ! 106: if (decexp < 0) ! 107: *buf++ = '0'; /* Units digit '0' */ ! 108: else do ! 109: *buf++ = *cp ? *cp++ : '0'; /* or integral part */ ! 110: while (decexp--); ! 111: if (prec == 0 || (isgfmt && *cp == '\0')) ! 112: return(buf); ! 113: *buf++ = '.'; /* '.' */ ! 114: while (prec-- > 0) { ! 115: if (isgfmt && *cp == '\0') ! 116: break; /* suppress trailing zeros */ ! 117: if (++decexp < 0) ! 118: *buf++ = '0'; /* put leading zero */ ! 119: else ! 120: *buf++ = *cp ? *cp++ : '0'; ! 121: } ! 122: return (buf); ! 123: } ! 124: ! 125: /* ! 126: * Convert nonnegative double 'd' to string of ASCII digits with no leading zeros ! 127: * (unless "0") and no trailing zeros, with precision 'prec' in format 'fmt'. ! 128: * Return a pointer to the converted string, usually (not always) in 'buf'. ! 129: * Store the decimal exponent indirectly through 'decexpp'. ! 130: * The first digit of the return value is implicitly followed by '.' ! 131: * and the return value is implicitly multiplied by 10 to the decimal exponent. ! 132: */ ! 133: char * ! 134: _dtoa(fmt, d, prec, decexpp, signp, buf) ! 135: int fmt; ! 136: double d; ! 137: int prec; ! 138: int *decexpp; ! 139: int *signp; ! 140: char *buf; ! 141: { ! 142: register char *cp; ! 143: register int digit; ! 144: register int decexp; ! 145: int ndigits; ! 146: int binexp; ! 147: double dexp; ! 148: ! 149: /* ! 150: * Force d >= 0.0. The "signp" arg is extraneous in the _dtefg() call, ! 151: * but is retained for the calls from ecvt() and fcvt(). Bah. ! 152: */ ! 153: if (d < 0.0) { ! 154: *signp = 1; ! 155: d = -d; ! 156: } ! 157: else ! 158: *signp = 0; ! 159: ! 160: /* Handle 0.0 as a special case. */ ! 161: if (d == 0.0) { ! 162: *decexpp = 0; ! 163: return("0"); ! 164: } ! 165: ! 166: /* Reduce d to range [1., 10) and set decexp accordingly. */ ! 167: /* Approximate the decimal exponent from the binary exponent. */ ! 168: /* Obscure but it makes floating output much more efficient. */ ! 169: frexp(d, &binexp); /* Find binary exponent */ ! 170: modf((--binexp)/LOG10B2, &dexp); /* Scale, take integer part */ ! 171: decexp = dexp; /* Convert to integer */ ! 172: d *= _pow10(-decexp); /* Reduce d by power of 10 */ ! 173: if (d >= 10.) { /* May be off by 1 place */ ! 174: ++decexp; ! 175: d *= 0.10; ! 176: } ! 177: *decexpp = decexp; /* Store the decimal exponent */ ! 178: ! 179: /* Compute the desired number of result digits. */ ! 180: if (fmt == 'e' || (fmt == 'g' && (decexp > 4 || decexp < -prec))) ! 181: ndigits = prec + 1; /* For 'e' format */ ! 182: else ! 183: ndigits = prec + decexp + 1; /* For 'f' format */ ! 184: if (ndigits <= 0) { /* No significant digits */ ! 185: if (ndigits == 0 && d > 5.0) { /* Round up to one digit */ ! 186: ++*decexpp; ! 187: return("1"); ! 188: } ! 189: *decexpp = 0; ! 190: return("0"); ! 191: } ! 192: else if (ndigits > L10P) ! 193: ndigits = L10P; /* Maximum precision */ ! 194: ! 195: /* Compute the result digits. */ ! 196: for (cp = buf; cp < &buf[ndigits] && d != 0.0; ) { ! 197: digit = (int) d; ! 198: *cp++ = digit + '0'; /* Store next digit */ ! 199: d = 10.0 * (d-digit); /* and reduce d accordingly */ ! 200: } ! 201: *cp = '\0'; /* NUL-terminate result */ ! 202: ! 203: /* Round up the result if appropriate. */ ! 204: if (d <= 5.0) { /* Do not round up */ ! 205: while (--cp != buf && *cp == '0') ! 206: *cp = '\0'; /* Strip a trailing '0' */ ! 207: return (buf); ! 208: } ! 209: while (cp-- != buf) { /* Round up */ ! 210: if (++*cp <= '9') /* Bump last digit */ ! 211: return (buf); ! 212: *cp = '\0'; /* Strip a trailing '0' */ ! 213: } ! 214: ++*decexpp; /* Bump exponent */ ! 215: return("1"); /* and return "1" */ ! 216: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.