Cin >> Fails with Bigger Numbers But Works with Smaller Ones

Why would we call cin.clear() and cin.ignore() after reading input?

The cin.clear() clears the error flag on cin (so that future I/O operations will work correctly), and then cin.ignore(10000, '\n') skips to the next newline (to ignore anything else on the same line as the non-number so that it does not cause another parse failure). It will only skip up to 10000 characters, so the code is assuming the user will not put in a very long, invalid line.

What happens when operator is trying to input a value bigger than a variable can contain?

On std::istream& std::istream::operator>>(std::istream&, int&), cppreference says:

Behaves as a FormattedInputFunction. After constructing and checking the sentry object, which may skip leading whitespace, extracts an integer value by calling std::num_get::get()

...

If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set. (since c++11)

It's not normative, but it does provide a decent summary of what is happening here.

FormattedInputFunctions will construct a sentry from the stream and check the value. If the sentry object evaluates as false, then no input is performed.

The sentry object will evaluate as false if, among other situations, the stream being operated on has the failbit set.


So, what's happening is this:

  1. The stream tries to read in an integer too large to hold in the int data type.
  2. The int passed into its function is set to the maximum possible value an int can store.
  3. The stream passed into the function has its failbit set.
  4. Further reads to the stream fail and do nothing, because the stream's failbit is set.

You can detect these overflow errors by checking the failbit and value of the integer after the read operation you are performing, as mentioned in the accepted answer to the question Read int from istream, detect overflow.

You can recover from these errors by unsetting the failbit with std::basic_ios::clear. Following a call to clear which unsets the failbit, further reads will behave as you expect.

Python. Code fails to work with larger numbers, but works with smaller numbers. Why?

Simple error. You need to use floor division:

c = c // 2

This will fix it. The original c = c/2 turns your c into float which fails for large numbers. Compare:

>>> int(914136090224822879032 / 2)
457068045112411422720
>>> 914136090224822879032 // 2
457068045112411439516

With that change, you will get:

>>> add_binary(800998058044843321128,113138032179979557904)
'1100011000111000101111110010101100001001000111000000001000001100111000'

if you want a short version:

def add_binary(a, b):
return '{:b}'.format(a+b)

How to handle wrong data type input

The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.

//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}

See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.

Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.

Checking cin input stream produces an integer

You can check like this:

int x;
cin >> x;

if (cin.fail()) {
//Not an int.
}

Furthermore, you can continue to get input until you get an int via:

#include <iostream>

int main() {

int x;
std::cin >> x;
while(std::cin.fail()) {
std::cout << "Error" << std::endl;
std::cin.clear();
std::cin.ignore(256,'\n');
std::cin >> x;
}
std::cout << x << std::endl;

return 0;
}

EDIT: To address the comment below regarding input like 10abc, one could modify the loop to accept a string as an input. Then check the string for any character not a number and handle that situation accordingly. One needs not clear/ignore the input stream in that situation. Verifying the string is just numbers, convert the string back to an integer. I mean, this was just off the cuff. There might be a better way. This won't work if you're accepting floats/doubles (would have to add '.' in the search string).

#include <iostream>
#include <string>

int main() {

std::string theInput;
int inputAsInt;

std::getline(std::cin, theInput);

while(std::cin.fail() || std::cin.eof() || theInput.find_first_not_of("0123456789") != std::string::npos) {

std::cout << "Error" << std::endl;

if( theInput.find_first_not_of("0123456789") == std::string::npos) {
std::cin.clear();
std::cin.ignore(256,'\n');
}

std::getline(std::cin, theInput);
}

std::string::size_type st;
inputAsInt = std::stoi(theInput,&st);
std::cout << inputAsInt << std::endl;
return 0;
}

std::cin input with spaces?

You have to use cin.getline():

char input[100];
cin.getline(input,sizeof(input));

Return an error for two inputs of numbers if not an integer

You need to check the error state of std::cin before you act on the value returned by operator>>. Try something more like this instead:

#include <iostream>
#include <fstream>
#include <limits>
using namespace std;

int main () {

int num1, num2; // two integers
int choice; // chosen integers
int ch1 = 0, ch2 = 0, ch3 = 0, ch4 = 0, ch5 = 0; // to keep track of chosen functions

//const for choice of menu
const int addition = 1,
substruction = 2,
multiplication = 3,
division = 4,
modulo = 5,
numberChange = 6;

//intro
cout << "This program has been made for arithmetic operations.\n";
cout << "Please choose two integers for arithmetic operations\n";

//return error if input is not integers
while (!(cin >> num1 >> num2)) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Error! Please enter only integers!\n";
}

do {
cout << "Choose number of the operation you want to do\n";
cout << "1. addition\n";
cout << "2. subtraction\n";
cout << "3. multiplication\n";
cout << "4. division\n";
cout << "5. modulo\n";
cout << "6. CHANGE OF NUMBERS\n";
cout << "To exit menu enter -1!\n";

//return error if input is not integer
while (!(cin >> choice)) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Error! Please enter only integers!\n";
}

// validate the input for right number
switch (choice) {
case 1:
cout << "Result: " << num1 << " + " << num2 << " = " << num1 + num2 << '\n';
ch1++;
break;
case 2:
cout << "Result: " << num1 << " - " << num2 << " = " << num1 - num2 << '\n';
ch2++;
break;
case 3:
cout << "Result: " << num1 << " * " << num2 << " = " << num1 * num2 << '\n';
ch3++;
break;
case 4:
cout << "Result: " << num1 << " / " << num2 << " = " << num1 / num2 << '\n';
ch4++;
break;
case 5:
cout << "Result: " << num1 << " % " << num2 << " = " << num1 % num2 << '\n';
ch5++;
break;
case 6:
cout << "Okay, you can choose different numbers\n";
while (!(cin >> num1 >> num2)) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Error! Please enter only integers!\n";
}
break;
case -1: {
ofstream myfile ("/Users/margaritakholostova/Desktop/us.txt");
if (myfile.is_open()) {
myfile << "Addition was selected " << ch1 << " times\n";
myfile << "Subtraction was selected " << ch2 << " times\n";
myfile << "Multiplication was selected " << ch3 << " times\n";
myfile << "Division was selected " << ch4 << " times\n";
myfile << "Modulo was selected " << ch5 << " times\n";
myfile.close();
}
else
cout << "Unable to open file\n";
return 0;
}

default:
cout << "Please choose a valid option from the menu (1-5)\n";
break;
}
}
while (true);
}


Related Topics



Leave a reply



Submit