7
\$\begingroup\$

Write getfloat, the floating-point analog of getint. What types does getfloat return as its function value?

gefloat would also return an integer value. Here is my solution:

int getfloat(double *pf) {
    int c, sign;
    double power;

    while(isspace(c = getch()))
        ;
    if(!isdigit(c) && c != EOF && c != '-' && c != '+' && c != '.') {
        ungetch(c); /* push the number back in buffer */
        return 0; /* not a valid number */
    }

    sign = (c == '-') ? -1 : 1;
    if(c == '-' || c == '+')
        c = getch();

    if(!isdigit(c) && c != '.') {
        ungetch(c);
        return 0; /* not a number */
    }

    for(*pf = 0.0; isdigit(c); c = getch())
        *pf = *pf * 10 + (c - '0');

    if(c == '.')
        c = getch();

    for(power = 1.0; isdigit(c); c = getch()) {
        *pf = *pf * 10 + (c - '0');
        power *= 10;
    }

    *pf *= sign;
    *pf /= power; /* moving the decimal point */

    if(c != EOF)
        ungetch(c);
    return c; /* it actually returns the value of the charachter that caused the break of the second for */
}

I have changed the type of the parameter *pf to double, thus it will handle the floating point represenation of a number. The condition of the first if-statement was extended, such that it will not push back in to the buffer a decimal point. The second for computes the decimal part of the number, storing the number of places that the decimal point should pe moved in the variable power. If there is no decimal part, power will have the value 1 - thus, nothing will change if I devide *pf by power when power is 1.

\$\endgroup\$

1 Answer 1

7
\$\begingroup\$
  1. It obviously does not handle NAN and INF. Maybe outside code's goals.

  2. Surprisingly does not handle exponential notation such as 1.23e+56.

  3. if(!isdigit(c) && c != '.') { returns a 0 implying "not a number" and ungets the offending c. But a potential + or - was all ready consumed and not available for alternative parsings. Not sure best way to handle, but maybe consider that once a non-white-space char is irrevocable consumed, this function should not return a error signal and should set *pf to _something_like 0 or NAN.

  4. Minor: The *pf /= power; approach fails with input such as 123.00000...(300+ zeros) as power or *pf already became INF.

  5. This is a pedantic point: Once you get about 17 (depends on double) decimal digits, the addition of (c - '0') to *pf * 10 becomes moot. To get a more accurate significand, forming the number right-to-left has precision advantages.

  6. The return c; could return 0 indicating "not a number" . Recommend an alternative return value scheme.

  7. ungetch is not in the C spec. Consider ungetc().

  8. With ungetc() "If the value of c equals that of the macro EOF, the operation fails and the input stream is unchanged." thus negating the need for the if(c != EOF). Still not bad to have there.

  9. The decimal point . is locale sensitive and could be , or something else. Use locale sensitive routines to determine the current decimal point.

  10. You are commended for for taking in "-0" and rendering -0.0 rather than 0.0.

  11. [Edit] IEEE_754-2008 Character_representation discusses the maximum number of non-zero leading digits to use when converting from text to a number. double is often a IEEE_754 binary64, so a maximum number to use is 17+3. This goes into point #3 above. Its a bit deep on how this affects things, but I'll just note it for those who want to delve into a portable robust solution.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.