Annotation of coherent/b/lib/libc/XSTDIO/ndpobj/_dtefg.c, revision 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.