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