Exercise 4-2

Extend atof to handle scientific notation of the form 123.45e-6 where a floating-point number may be followed by e or E and an optionally signed exponent.

After all the digits have been read in, we check if the number is followed by an e (upper or lowercase.) If so, we first store the sign of the exponent in exp_sign (we can safely assume the exponent is positive if there is no sign) and read in the digits into the integer exp. This is done in the same way as earlier in atof. Finally, we multiply exp by exp_sign to get the signed value of the exponent.

    /* atof:  convert string s to double */
    double atof(char s[])
    {
        double val, power;
        int i, sign, exp, exp_sign;
    
        for (i = 0; isspace(s[i]); i++)  /* skip white space */
            ;
        sign = (s[i] == '-') ? -1 : 1;
        if (s[i] == '+' || s[i] == '-')
            i++;
        for (val = 0.0; isdigit(s[i]); i++)
            val = 10.0 * val + (s[i] - '0');
        if (s[i] == '.')
            i++;
        for (power = 1.0; isdigit(s[i]); i++) {
            val = 10.0 * val + (s[i] - '0');
            power *= 10.0;
        }
        if (tolower(s[i]) == 'e') {
            ++i;
            exp_sign = (s[i] == '-') ? -1 : 1;
            if (s[i] == '+' || s[i] == '-')
                ++i;
            for (exp = 0; isdigit(s[i]); ++i)
                exp = 10 * exp + (s[i] - '0');
            exp *= exp_sign;
        }
        return sign * val / power;
    }

Now that we have the value of the exponent, we can modify the value of power. There are two scenarios: if exp is positive, we multiply power by 10 exp times. On the other hand, if exp is negative, we divide power by 10 |exp| times.

    /* atof:  convert string s to double */
    double atof(char s[])
    {
        double val, power;
        int i, sign, exp, exp_sign;
    
        for (i = 0; isspace(s[i]); i++)  /* skip white space */
            ;
        sign = (s[i] == '-') ? -1 : 1;
        if (s[i] == '+' || s[i] == '-')
            i++;
        for (val = 0.0; isdigit(s[i]); i++)
            val = 10.0 * val + (s[i] - '0');
        if (s[i] == '.')
            i++;
        for (power = 1.0; isdigit(s[i]); i++) {
            val = 10.0 * val + (s[i] - '0');
            power *= 10.0;
        }
        if (tolower(s[i]) == 'e') {
            ++i;
            exp_sign = (s[i] == '-') ? -1 : 1;
            if (s[i] == '+' || s[i] == '-')
                ++i;
            for (exp = 0; isdigit(s[i]); ++i)
                exp = 10 * exp + (s[i] - '0');
            exp *= exp_sign;
            for (; exp < 0; ++exp)
                power *= 10.0;
            for (; exp > 0; --exp)
                power /= 10.0;
        }
        return sign * val / power;
    }