Annotation of 43BSD/contrib/icon/rt/cvnum.c, revision 1.1

1.1     ! root        1: #include "../h/ctype.h"
        !             2: #include "../h/rt.h"
        !             3: #include <math.h>
        !             4: 
        !             5: /*
        !             6:  * cvnum - convert the value represented by d into a numeric quantity and
        !             7:  *  place the value into *result.  T_LONGINT is returned for integer and
        !             8:  *  long integer results; T_REAL for real results, and NULL is returned
        !             9:  *  if d can't be converted to a numeric quantity.
        !            10:  */
        !            11: 
        !            12: cvnum(d, result)
        !            13: register struct descrip *d;
        !            14: union numeric *result;
        !            15:    {
        !            16:    char sbuf[MAXSTRING];
        !            17:    extern char *cvstr();
        !            18: 
        !            19:    DeRef(*d)
        !            20: 
        !            21:    if (QUAL(*d)) {
        !            22:       /*
        !            23:        * d is a string.  Convert it into an integer by first converting
        !            24:        *  it into a C-style string and then converting that string into
        !            25:        *  an integer with ston.
        !            26:        */
        !            27:       qtos(d, sbuf);
        !            28:       return (ston(sbuf, result));
        !            29:       }
        !            30: 
        !            31:    switch (TYPE(*d)) {
        !            32:       case T_INTEGER:
        !            33:          /*
        !            34:           * d is already an integer.  Cast the value into a long.
        !            35:           */
        !            36:          result->integer = (long)INTVAL(*d);
        !            37:          return (T_LONGINT);
        !            38: #ifdef LONGS
        !            39:       case T_LONGINT:
        !            40:          /*
        !            41:           * d is a long integer.  Assign it to *i and return.
        !            42:           */
        !            43:          result->integer = BLKLOC(*d)->intval;
        !            44:          return (T_LONGINT);
        !            45: #endif LONGS
        !            46: 
        !            47:       case T_REAL:
        !            48:          /*
        !            49:           * d is a real number, return it.
        !            50:           */
        !            51:          result->real = BLKLOC(*d)->realblk.realval;
        !            52:          return (T_REAL);
        !            53:       default:
        !            54:          /*
        !            55:           * d is not already numeric, try to convert it to a string and
        !            56:           *  then try to convert the string to an integer.
        !            57:           */
        !            58:          if (cvstr(d, sbuf) == NULL)
        !            59:             return (NULL);
        !            60:          return (ston(STRLOC(*d), result));
        !            61:       }
        !            62:    }
        !            63: 
        !            64: #define BIG 72057594037927936.  /* numbers larger than 2^56 lose precision */
        !            65: 
        !            66: /*
        !            67:  * ston - convert a string to a numeric quantity if possible.
        !            68:  */
        !            69: static ston(s, result)
        !            70: register char *s;
        !            71: union numeric *result;
        !            72:    {
        !            73:    register int c;
        !            74:    int realflag = 0;   /* indicates a real number */
        !            75:    char msign = '+';   /* sign of mantissa */
        !            76:    char esign = '+';   /* sign of exponent */
        !            77:    double mantissa = 0;        /* scaled mantissa with no fractional part */
        !            78:    int scale = 0;      /* number of decimal places to shift mantissa */
        !            79:    int digits = 0;     /* total number of digits seen */
        !            80:    int sdigits = 0;    /* number of significant digits seen */
        !            81:    int exponent = 0;   /* exponent part of real number */
        !            82:    double fiveto;      /* holds 5^scale */
        !            83:    double power;       /* holds successive squares of 5 to compute fiveto */
        !            84:    extern int errno;
        !            85: 
        !            86:    c = *s++;
        !            87: 
        !            88:    /*
        !            89:     * Skip leading white space.
        !            90:     */
        !            91:    while (isspace(c))
        !            92:       c = *s++;
        !            93: 
        !            94:    /*
        !            95:     * Check for sign.
        !            96:     */
        !            97:    if (c == '+' || c == '-') {
        !            98:       msign = c;
        !            99:       c = *s++;
        !           100:       }
        !           101: 
        !           102:    /*
        !           103:     * Get integer part of mantissa.
        !           104:     */
        !           105:    while (isdigit(c)) {
        !           106:       digits++;
        !           107:       if (mantissa < BIG) {
        !           108:          mantissa = mantissa * 10 + (c - '0');
        !           109:          if (mantissa > 0.0)
        !           110:             sdigits++;
        !           111:          }
        !           112:       else
        !           113:          scale++;
        !           114:       c = *s++;
        !           115:       }
        !           116: 
        !           117:    /*
        !           118:     * Check for based integer.
        !           119:     */
        !           120:    if (c == 'r' || c == 'R')
        !           121:       return (radix(msign, (int)mantissa, s, result));
        !           122: 
        !           123:    /*
        !           124:     * Get fractional part of mantissa.
        !           125:     */
        !           126:    if (c == '.') {
        !           127:       realflag++;
        !           128:       c = *s++;
        !           129:       while (isdigit(c)) {
        !           130:          digits++;
        !           131:          if (mantissa < BIG) {
        !           132:             mantissa = mantissa * 10 + (c - '0');
        !           133:             scale--;
        !           134:             if (mantissa > 0.0)
        !           135:                sdigits++;
        !           136:             }
        !           137:          c = *s++;
        !           138:          }
        !           139:       }
        !           140: 
        !           141:    /*
        !           142:     * Check that at least one digit has been seen so far.
        !           143:     */
        !           144:    if (digits == 0)
        !           145:       return (NULL);
        !           146: 
        !           147:    /*
        !           148:     * Get exponent part.
        !           149:     */
        !           150:    if (c == 'e' || c == 'E') {
        !           151:       realflag++;
        !           152:       c = *s++;
        !           153:       if (c == '+' || c == '-') {
        !           154:          esign = c;
        !           155:          c = *s++;
        !           156:          }
        !           157:       if (!isdigit(c))
        !           158:          return (NULL);
        !           159:       while (isdigit(c)) {
        !           160:          exponent = exponent * 10 + (c - '0');
        !           161:          c = *s++;
        !           162:          }
        !           163:       scale += (esign == '+')? exponent : -exponent;
        !           164:       }
        !           165: 
        !           166:    /*
        !           167:     * Skip trailing white space.
        !           168:     */
        !           169:    while (isspace(c))
        !           170:       c = *s++;
        !           171: 
        !           172:    /*
        !           173:     * Check that entire string has been consumed.
        !           174:     */
        !           175:    if (c != '\0')
        !           176:       return (NULL);
        !           177: 
        !           178:    /*
        !           179:     * Test for integer.
        !           180:     */
        !           181:    if (!realflag && mantissa >= MINLONG && mantissa <= MAXLONG) {
        !           182:       result->integer = (msign == '+')? mantissa : -mantissa;
        !           183:       return (T_LONGINT);
        !           184:       }
        !           185: 
        !           186:    /*
        !           187:     * Rough tests for overflow and underflow.
        !           188:     */
        !           189:    if (sdigits + scale > LGHUGE)
        !           190:       return (NULL);
        !           191: 
        !           192:    if (sdigits + scale < -LGHUGE) {
        !           193:       result->real = 0.0;
        !           194:       return (T_REAL);
        !           195:       }
        !           196: 
        !           197:    /*
        !           198:     * Put the number together by multiplying the mantissa by 5^scale and
        !           199:     *  then using ldexp() to multiply by 2^scale.
        !           200:     */
        !           201: 
        !           202: #ifdef PDP11
        !           203:    /*
        !           204:     * Load floating point status register on PDP-11.
        !           205:     */
        !           206:    ldfps(0200);
        !           207: #endif PDP11
        !           208:    exponent = (scale > 0)? scale : -scale;
        !           209:    fiveto = 1.0;
        !           210:    power = 5.0;
        !           211:    for (;;) {
        !           212:       if (exponent & 01)
        !           213:          fiveto *= power;
        !           214:       exponent >>= 1;
        !           215:       if (exponent == 0)
        !           216:          break;
        !           217:       power *= power;
        !           218:       }
        !           219:    if (scale > 0)
        !           220:       mantissa *= fiveto;
        !           221:    else
        !           222:       mantissa /= fiveto;
        !           223: 
        !           224:    errno = 0;
        !           225:    mantissa = ldexp(mantissa, scale);
        !           226: #ifdef PDP11
        !           227:    /*
        !           228:     * Load floating point status register on PDP-11
        !           229:     */
        !           230:    ldfps(03200);
        !           231: #endif PDP11
        !           232:    if (errno > 0 && mantissa > 0)
        !           233:       /*
        !           234:        * ldexp caused overflow.
        !           235:        */
        !           236:       return (NULL);
        !           237: 
        !           238:    result->real = (msign == '+')? mantissa : -mantissa;
        !           239:    return (T_REAL);
        !           240:    }
        !           241: 
        !           242: /*
        !           243:  * radix - convert string s in radix r into an integer in *result.  sign
        !           244:  *  will be either '+' or '-'.
        !           245:  */
        !           246: static radix(sign, r, s, result)
        !           247: char sign;
        !           248: register int r;
        !           249: register char *s;
        !           250: union numeric *result;
        !           251:    {
        !           252:    register int c;
        !           253:    long num;
        !           254: 
        !           255:    if (r < 2 || r > 36)
        !           256:       return (NULL);
        !           257: 
        !           258:    c = *s++;
        !           259:    num = 0L;
        !           260:    while (isalnum(c)) {
        !           261:       c = tonum(c);
        !           262:       if (c >= r)
        !           263:          return (NULL);
        !           264:       num = num * r + c;
        !           265:       c = *s++;
        !           266:       }
        !           267: 
        !           268:    while (isspace(c))
        !           269:       c = *s++;
        !           270: 
        !           271:    if (c != '\0')
        !           272:       return (NULL);
        !           273: 
        !           274:    result->integer = (sign == '+')? num : -num;
        !           275:    return (T_LONGINT);
        !           276:    }

unix.superglobalmegacorp.com

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