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
NAN
andINF
. Maybe outside code's goals.Surprisingly does not handle exponential notation such as 1.23e+56.
if(!isdigit(c) && c != '.') {
returns a0
implying "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-spacechar
is irrevocable consumed, this function should not return a error signal and should set*pf
to _something_like 0 or NAN.Minor: The
*pf /= power;
approach fails with input such as 123.00000...(300+ zeros) aspower
or*pf
already became INF.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.The
return c;
could return0
indicating "not a number" . Recommend an alternative return value scheme.ungetch
is 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.0
rather 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.
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.