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