19

How would I check if the input is really a double?

double x;

while (1) {
    cout << '>';
    if (cin >> x) {
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
    }
}
//do other stuff...

The above code infinitely outputs the Invalid Input! statement, so its not prompting for another input. I want to prompt for the input, check if it is legitimate... if its a double, go on... if it is NOT a double, prompt again.

Any ideas?

Hristo
  • 45,559
  • 65
  • 163
  • 230

6 Answers6

16

Try this:

while (1) {
  if (cin >> x) {
      // valid number
      break;
  } else {
      // not a valid number
      cout << "Invalid Input! Please input a numerical value." << endl;
      cin.clear();
      while (cin.get() != '\n') ; // empty loop
  }
}

This basically clears the error state, then reads and discards everything that was entered on the previous line.

casablanca
  • 69,683
  • 7
  • 133
  • 150
  • is this inside the `while(1)` loop? – Hristo Jul 18 '10 at 01:56
  • Yes, inside your existing loop. I've just reproduced the inner part. – casablanca Jul 18 '10 at 01:57
  • Ok that works. Can you explain the logic behind the empty loop? What exactly is going on in there? What does `get()` do? – Hristo Jul 18 '10 at 02:01
  • Since `cin >> x` expects a number, you need to clear any invalid input that was previously entered. `get()` simply reads one character at a time, and the loop continues until it reaches the end of the line. – casablanca Jul 18 '10 at 02:03
  • Thank you. That makes sense... seems inefficient but since I'm dealing with a small number of characters, reading to the end of the line won't be difficult. I know there is a difference between Windows and UNIX in ending a line... something like `\r` in Windows? Will your solution work in both environments? – Hristo Jul 18 '10 at 02:06
  • 3
    Instead of `while(cin.get() != '\n');`, I'd just use `cin.sync();`. It's more readable in my opinion. – chaosTechnician Jul 18 '10 at 02:08
  • 1
    In UNIX, it's a `\r\n`, so there's still a `\n` at the end. So yes, it will work. – casablanca Jul 18 '10 at 02:10
  • @Hristo: From http://cplusplus.com/reference/iostream/istream/sync/ It "synchronizes the buffer associated with the stream to its controlled input sequence. This effectively means that the unread characters in the buffer are discarded." – chaosTechnician Jul 18 '10 at 02:12
  • @chaosTechnician: +1. I had no idea there was a ready-made method to do this. @Hristo: I just searched for `sync` and here's a [reference](http://www.cplusplus.com/reference/iostream/istream/sync/). I guess you could replace the `while` loop with a single call to `sync` then. – casablanca Jul 18 '10 at 02:13
  • 2
    @chaosTechnician, cin.sync() doesn't work for me when I try this example. the while(cin.get() != '\n'); does though. Any idea why? – Mahmoud Abdelkader Jul 18 '10 at 06:48
  • @Mahmoud: When you say it doesn't work, what is it doing? The above code (with `sync()` used instead of the loop) works fine for me using VS2008's compiler and GCC. Are you replacing more than just the loop with `sync()` or using a non-standard compiler? – chaosTechnician Jul 18 '10 at 19:15
  • I'm using g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3. I copy and pasted the Hristo's code and tried it and it still giving me an infinite loop of 'Invalid Input! Please..." – Mahmoud Abdelkader Jul 19 '10 at 01:56
  • 1
    No, it's written before: cin.sync(); Here's a snippet of the code: int main(int argc, char *argv[]) { double x; while (1) { cout << '>'; if (cin >> x) { break; } else { // not a valid number cout << "Invalid Input! Please input a numerical value." << endl; cin.clear(); cin.sync(); // while(cin.get() != '\n'); } } cout << "you entered: " << x << endl; return 0; } – Mahmoud Abdelkader Jul 20 '10 at 18:31
  • Maybe it is a bug in the GNU version? I really hate cin. For many years now. `getline()` function (sic) for the win. Nothing else worked for me yet. – Notinlist May 05 '12 at 17:38
  • @MahmoudAbdelkader cin.sync() is pain by design: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46624 . The newline is different on various platforms and we may want to stop at spaces too, so `cin.ignore()` is also hard. I decided to solve this issue of flushing a bit of input buffer by reading a word into a dummy `std::string`. Relatively simple and effective. – Notinlist May 05 '12 at 17:57
2

I would use:

double x;

while (!(std::cin >> x)) {
  std::cin.clear();
  std::cin.ignore(2147483647, '\n');
  std::cout << "Error.\n";
}

or

double x;

while ((std::cout << "> ") && !(std::cin >> x)) {
  std::cin.clear();
  std::cin.ignore(2147483647, '\n');
  std::cout << "Error.\n";
}
mmontoya
  • 403
  • 3
  • 9
1

failbit will be set after using an extraction operator if there was a parse error, there are a couple simple test functions good and fail you can check. They are exactly the opposite of each other because they handle eofbit differently, but that's not an issue in this example.

Then, you have to clear failbit before trying again.

As casablanca says, you also have to discard the non-numeric data still left in the input buffer.

So:

double x;

while (1) {
    cout << '>';
    cin >> x;
    if (cin.good())
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
        cin.clear();
        cin.ignore(100000, '\n');
    }
}
//do other stuff...
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • this is still causing the infinite loop to print the `Invalid Input!`... its not prompting for another input. – Hristo Jul 18 '10 at 01:50
  • What does the `cin.ignore()` do? – Hristo Jul 18 '10 at 02:07
  • Same thing as casablanca's loop, it throws away all characters up to and including the newline to get rid of whatever non-numeric data caused the first extraction to fail. – Ben Voigt Jul 18 '10 at 02:18
0
#include <iostream>
#include <string>

bool askForDouble(char const *question, double &ret)
{
        using namespace std;
        while(true)
        {
                cout << question << flush;
                cin >> ret;
                if(cin.good())
                {
                        return true;
                }
                if(cin.eof())
                {
                        return false;
                }
                // (cin.fail() || cin.bad()) is true here
                cin.clear();  // clear state flags
                string dummy;
                cin >> dummy; // discard a word
        }
}

int main()
{
        double x;
        if(askForDouble("Give me a floating point number! ",x))
        {
                std::cout << "The double of it is: " << (x*2) << std::endl;
        } else
        {
                std::cerr << "END OF INPUT" << std::endl;
        }
        return 0;
}
Notinlist
  • 16,144
  • 10
  • 57
  • 99
  • 1
    Input validation should have been an easier task to do. It makes it very hard to teach newbies and help them enjoy what they are doing. I would like to see a bulletproof and still useful tutorial on cin and cout for newbies. – Notinlist May 05 '12 at 18:25
0
bool is_double(double val)
{
bool answer;
double chk;
int double_equl = 0;     
double strdouble = 0.0;
strdouble = val;           
double_equl = (int)val;
chk = double_equl / strdouble;
if (chk == 1.00)
{
 answer = false; // val is integer
 return answer;
} else {
answer = true;  // val is double
return answer;
}
}
Denys Shabelnyk
  • 125
  • 2
  • 11
-1

One way is to check for floating number equality.

double x;

while (1) {
    cout << '>';
    cin >> x;
    if (x != int(x)) {
        // valid number
        break;
    } else {
        // not a valid number
        cout << "Invalid Input! Please input a numerical value." << endl;
    }
}
cpx
  • 17,009
  • 20
  • 87
  • 142
  • how does this check for type `double`? – Hristo Jul 18 '10 at 01:58
  • 1
    This just checks if the input had a fractional part, which is probably not what was meant by the question. – Ben Voigt Jul 18 '10 at 02:00
  • Yeah, most of us know what Hristo meant but this answer does address the question he asked: "How would I check if the input is really a double?" Interpreting that as, "I assume I'm getting numbers, how do I ensure they aren't whole numbers?" makes this a perfectly useful answer. No need to downvote, imo. – chaosTechnician Jul 18 '10 at 19:21
  • @chaosTechnician The error message says "Invalid Input! Please input a numerical value.". Whole and not-whole numbers are both "numerical values". So this answer's intention is very unclear for me. Not down-voting anyway. :-) – Notinlist May 05 '12 at 18:21