Probably simple C++ question

Started by
11 comments, last by random_thinker 16 years, 6 months ago
I an trying to input a variable with type double but don't know how to check to make sure the input is double and not something else. Could someone tell me how to do this?
Advertisement
What about if(variable%1!=0)
Quote:Original post by PCosmin89
What about if(variable%1!=0)


Umm, no. Modular arithmetic only works on integral types (int, short, long, etc) in C++, and even if that was allowed, what if the value was 10.0?
Quote:
What about if(variable%1!=0)

% is only valid for integers. This doesn't answer the question.

Quote:
Could someone tell me how to do this?

Presuming you are using std::cin for input, then just:
double d = 0.0;std::cin >> d;

Now, if you want to make sure the user enters something that is, in fact, a double (in the above code if they enter somebody bogus you will get unexpected results), you must first read the input as a string, then parse it. boost::lexical_cast is great for this. If you don't have Boost, get it. Or use something like
bool is_double(const std::string &input){  std::istringstream marshaller(input);  double dummy;  marshaller >> dummy;  return !marshaller.fail();}
Quote:Original post by jpetrie
Or use something like
bool is_double(const std::string &input){  std::istringstream marshaller(input);  double dummy;  marshaller >> dummy;  return !marshaller.fail();}


This is actually no different from
double x;if (cin >> x) {    // ok}else {    // bad}

In that both will seem ok if the user enters something like "42asdf" -- x = 42, but "asdf" will still be left in the buffer. If you really need to verify that what the user entered is a real number and absolutely nothing else, that's kinda difficult. You can use atof, but that returns 0.0 in case of an error. So you'd have to compare it to the stringstream conversion result, to make sure that the user didn't actually enter 0.
How about...

// Evaluates whether a "C" string is a real.bool isReal(const char ch[]){    unsigned i = 0;    bool has_point = false, has_sign = false;    while ( ch != '\0' )    {        // Look for a digit.        if ( !std::isdigit(ch) )        {            switch (ch)            {                case '.':                    if ( has_point == true )                    {                        // Oops, allowed one occurrence.                        return false;                    }                    else                    {                        // Found the first point.                        has_point = true;                    }                    break;                case '-':                    if ( has_sign == true )                    {                        // Oops, allowed one occurrence.                        return false;                    }                    else                    {                        // Found the first sign.                        has_sign = true;                    }                    break;                case '+':                    if ( has_sign == true )                    {                        // Oops, allowed one occurrence.                        return false;                    }                    else                    {                        // Found the first sign.                        has_sign = true;                    }                    break;                default:                    // Oops, no number, no point, no minus, no plus.                    return false;            }        }        ++i;    }    // Has point, sign and at least one number.    if ( has_point && has_sign && i > 2 )        return true;    // Has point and at least one number.    if ( has_point && i > 1 )        return true;    // Has number, but nothing else.    return false;}


Rules:

1. Can have either a + or - sign or none, but not both signs, or it fails.
2. Must have decimal point, or else assumed to be an integer, and it fails.
3. Must have at least one digit, or it fails.
4. If it has anything other than +/-, digits and a point, then it fails.

--random
--random_thinkerAs Albert Einstein said: 'Imagination is more important than knowledge'. Of course, he also said: 'If I had only known, I would have been a locksmith'.
Quote:Original post by random_thinker
How about...

*** Source Snippet Removed ***

Rules:

1. Can have either a + or - sign or none, but not both signs.
2. Must have decimal point, or else assumed to be an integer.
3. Must have at least one number.
4. If it has anything other than +/-, digits and a point, then it fails.

--random


Consider:
45.+0
Quote:Original post by drakostar
Quote:Original post by jpetrie
Or use something like
bool is_double(const std::string &input){  std::istringstream marshaller(input);  double dummy;  marshaller >> dummy;  return !marshaller.fail();}


This is actually no different from
*** Source Snippet Removed ***
In that both will seem ok if the user enters something like "42asdf" -- x = 42, but "asdf" will still be left in the buffer. If you really need to verify that what the user entered is a real number and absolutely nothing else, that's kinda difficult. You can use atof, but that returns 0.0 in case of an error. So you'd have to compare it to the stringstream conversion result, to make sure that the user didn't actually enter 0.


It is quite different. Your one tries to interpret a double straight from std::cin, which if it fails you must reset the streams state and possibly ignore characters from the stream. I prefer to read in a string and then do the conversion as a separate step.

@random_thinker

what about "3E-3". Also, why not std::string?
If you want to check that there are no additional characters left in the string after reading the double, you can add a check to jpetrie's solution:
bool is_double(const std::string &input) {  std::istringstream marshaller(input);  double dummy;  marshaller >> dummy;  return !marshaller.fail() && (marshaller.rdbuf()->in_avail() == 0);}
Quote:
Consider:
45.+0


Quote:
what about "3E-3". Also, why not std::string?


Good points, could alter the logic to allow signs only at the beginning of the sequence to solve this potential problem. However, it is a lightweight and reliable approach even though it's very C-like. I couldn't be bothered to permit 'E-3' type constructs.

Could use std::string if you wanted, with a few alterations. I have used this primarily with std::getline() and feed the resulting string.c_str() to it.

--random

What about something like:

// Declare a double.double d=0;// Reference character set.const std::string double_chars("0123456789Ee-+.");// Make a cache.std::string cache; // Fill the cache.std::getline(std::cin,cache);// Check for any non-double characters.if (cache.find_first_not_of(double_chars) == std::string::npos){       // All characters are in reference set.     d=strtod(cache.c_str(),0);}else{     // Fail.}


[Edited by - random_thinker on September 28, 2007 5:56:17 PM]
--random_thinkerAs Albert Einstein said: 'Imagination is more important than knowledge'. Of course, he also said: 'If I had only known, I would have been a locksmith'.

This topic is closed to new replies.

Advertisement