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.
1 Answer 1
It obviously does not handle
NANandINF. Maybe outside code's goals.Surprisingly does not handle exponential notation such as 1.23e+56.
if(!isdigit(c) && c != '.') {returns a0implying "not a number" and ungets the offendingc. 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-spacecharis irrevocable consumed, this function should not return a error signal and should set*pfto _something_like 0 or NAN.Minor: The
*pf /= power;approach fails with input such as 123.00000...(300+ zeros) aspoweror*pfalready became INF.This is a pedantic point: Once you get about 17 (depends on
double) decimal digits, the addition of(c - '0')to*pf * 10becomes moot. To get a more accurate significand, forming the number right-to-left has precision advantages.The
return c;could return0indicating "not a number" . Recommend an alternative return value scheme.ungetchis not in the C spec. Considerungetc().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 theif(c != EOF). Still not bad to have there.The decimal point
.is locale sensitive and could be,or something else. Use locale sensitive routines to determine the current decimal point.You are commended for for taking in
"-0"and rendering-0.0rather than0.0.[Edit] IEEE_754-2008 Character_representation discusses the maximum number of non-zero leading digits to use when converting from text to a number.
doubleis 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.