strtod usage for "just the number"?

D

David Mathog

The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number. In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is:

char *atoken;
char *to;
double dtmp;
/* lots of other stuff, generating atoken */
errno=0;
dtmp=strtod(atoken,&to);
if(errno || !to || *to != '\0'){
fprintf(stderr,"fatal error: incorrect number syntax
%s",atoken);
}

It works but isn't very pretty, what with 3 tests for the various
failure modes. Is there another way to go about this, more along the
lines of:

if(cvtS2D(atoken,&dtmp)){
}

?
Where the hypothetical conversion function returns 0 if the input
string is just a number, and something
else for all the other cases?

Thanks,

David Mathog
 
F

Fred

The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number.  In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is:

char *atoken;
char *to;
double dtmp;
       /* lots of other stuff, generating atoken */
        errno=0;
        dtmp=strtod(atoken,&to);
        if(errno || !to || *to != '\0'){
          fprintf(stderr,"fatal error: incorrect number syntax
%s",atoken);
        }

It works but isn't very pretty, what with 3 tests for the various
failure modes.  Is there another way to go about this, more along the
lines of:

  if(cvtS2D(atoken,&dtmp)){
  }

?
Where the hypothetical conversion function returns 0 if the input
string is just a number, and something
else for all the other cases?

strtod only sets errno if a range error occurred, so you do not need
that check to determine whether the field had bad characters in it.

You do not need the check (*to != '\0') since if 'to' is not NULL, it
points to the first unused character, which is guaranteed to be
something other than the NUL character.

That leaves you with:
if ( to ) { ... }
 
D

David Resnick

The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number.  In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is:

char *atoken;
char *to;
double dtmp;
       /* lots of other stuff, generating atoken */
        errno=0;
        dtmp=strtod(atoken,&to);
        if(errno || !to || *to != '\0'){
          fprintf(stderr,"fatal error: incorrect number syntax
%s",atoken);
        }

It works but isn't very pretty, what with 3 tests for the various
failure modes.  Is there another way to go about this, more along the
lines of:

  if(cvtS2D(atoken,&dtmp)){
  }

?
Where the hypothetical conversion function returns 0 if the input
string is just a number, and something
else for all the other cases?

Why not just write your own function that does what the one above
does?
Lets you also control whether things that strtod will accept like
NAN or INFINITY or hex forms should count as "numbers".

-David
 
B

Ben Bacarisse

Fred said:
strtod only sets errno if a range error occurred, so you do not need
that check to determine whether the field had bad characters in it.

You do not need the check (*to != '\0') since if 'to' is not NULL, it
points to the first unused character, which is guaranteed to be
something other than the NUL character.

That leaves you with:
if ( to ) { ... }

I don't think that's right. If the programmer passes a valid pointer
as the second argument, it will get set to something -- either the value
of the first argument if no conversion could be done or to point just
past the converted data (even if that is a null byte).

As a result 'to == atoken || *to' is a sufficient test for failure in
this case.
 
F

Fred

I don't think that's right.  If the programmer passes a valid pointer
as the second argument, it will get set to something -- either the value
of the first argument if no conversion could be done or to point just
past the converted data (even if that is a null byte).

As a result 'to == atoken || *to' is a sufficient test for failure in
this case.

You're right. The first test (to==token) is needed in case 'token'
is empty, in which case *to is '\0', so just checking *to is
not sufficient to test for failure.
 
L

lawrence.jones

David Mathog said:
The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number. In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is:

char *atoken;
char *to;
double dtmp;
/* lots of other stuff, generating atoken */
errno=0;
dtmp=strtod(atoken,&to);
if(errno || !to || *to != '\0'){
fprintf(stderr,"fatal error: incorrect number syntax %s",atoken);
}

That isn't quite correct. strtod() will never set "to" to a null
pointer, but it will set it equal to atoken if no conversion could be
performed.
It works but isn't very pretty, what with 3 tests for the various
failure modes. Is there another way to go about this, more along the
lines of:

if(cvtS2D(atoken,&dtmp)){
}

int cvtS2D(const char * restrict p, double * restrict d)
{
char *q;
errno = 0;
*d = strtod(p, &q);
return (errno != 0 || q == p || *q != '\0');
}
 
K

katmac

The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number.  In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is:

char *atoken;
char *to;
double dtmp;
       /* lots of other stuff, generating atoken */
        errno=0;
        dtmp=strtod(atoken,&to);
        if(errno || !to || *to != '\0'){
          fprintf(stderr,"fatal error: incorrect number syntax
%s",atoken);
        }

It works but isn't very pretty, what with 3 tests for the various
failure modes.  Is there another way to go about this, more along the
lines of:

  if(cvtS2D(atoken,&dtmp)){
  }

?
Where the hypothetical conversion function returns 0 if the input
string is just a number, and something
else for all the other cases?

Thanks,

David Mathog

char junk;
return !(sscanf( atoken, "%lf%c", dtmp, &junk ) == 1);

The same pattern can be used for anything sscanf can decode (which is
quite a lot)
 
J

Jorgen Grahn

The C string to double conversion functions all seem to operate on the
front of the input string, turning as much of it is as possible into a
number. In a situation where the string should be entirely the
number, and nothing should follow it, the best I have come up with to
handle this case is: ....
It works but isn't very pretty, what with 3 tests for the various
failure modes. Is there another way to go about this, more along the
lines of:

if(cvtS2D(atoken,&dtmp)){
}

With these functions I tend to prefer returning the value and
passing a pointer to an errno-like error:

double cvtS2D(const char* buf, int* error);

int err = 0;
const double foo = cvsS2D(buf, &err);
const double bar = cvsS2D(buf2, &err);
if(err) // at least one input was broken

Although tastes (and usage patterns) vary.

/Jorgen
 
K

Keith Thompson

katmac said:
char junk;
return !(sscanf( atoken, "%lf%c", dtmp, &junk ) == 1);

The same pattern can be used for anything sscanf can decode (which is
quite a lot)

Unfortunately, if the string being scanned represents a number
outside the range of the target type, the behavior of sscanf is
undefined. See C99 7.19.6.2p10 (it's split across pages in n1256).
 
D

David Mathog

With these functions I tend to prefer returning the value and
passing a pointer to an errno-like error:

   double cvtS2D(const char* buf, int* error);

   int err = 0;
   const double foo = cvsS2D(buf, &err);
   const double bar = cvsS2D(buf2, &err);
   if(err) // at least one input was broken

Although tastes (and usage patterns) vary.

Right, styles vary. I would have done that like:

if(!cvtS2D(buf1,&dtmp1)){ boom("message1"); }
if(!cvtS2D(buf2,&dtmp2)){ boom("message2"); }

Either way, the important part is that the function returns ONE
unambiguous status value, which I think is better than having to check
multiple values to see if there was a problem or not. There are a lot
of C functions that follow the second path, including and especially
all those that depend on errno,
where one must look at one value for "the operation did not work (or
maybe it did but this might be a special case)" and another value for
"the problem was (or wasn't) ...". For instance, fscanf returning
EOF.

Regards,

David Mathog
 
D

David Mathog

strtod only sets errno if a range error occurred, so you do not need
that check to determine whether the field had bad characters in it.

Interestingly, it sets errno when the input is "[+-]inf" or "nan".
The conversion is correct, but it sets EDOM.
You do not need the check  (*to != '\0') since if 'to' is not NULL, it
points to the first unused character, which is guaranteed to be
something other than the NUL character.

That leaves you with:
   if ( to ) { ... }

No it doesn't (at least if (...) is supposed to be the error code):

dtmp = strtod("foo",&to);

has "to" as not NULL and it points to 'f', because nothing was
converted.

So if you want to be able to accept any valid number, including inf
and nan,
this seems to be the way to go:

dtmp=strtod(atoken,&to);
if(!to || *to){ fprintf(stderr,"PROBLEM\n"); }

Again, this is only if atoken is to hold exactly one valid double, and
nothing else.

Regards,

David Mathog
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top