Annotation of coherent/b/lib/libc/stdio/_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: #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 */

unix.superglobalmegacorp.com

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