Annotation of coherent/b/lib/libc/XSTDIO/ndpobj/_dtefg.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.