Search code examples
c++stliostreamcin

A question about the standard input stream std::cin and how it parses out double and ints


i am reading programming: principles and practice using c++. Currently im doing exercices for chapter 3, however one kind of stumped me. Now i was able to get the code working and all, but i was perplexed more about the programs reaction to my input.

Here's the question: Write a program that prompts the user to enter two integer values. Store these values in int variables named val1 and val2. Write your program to determine the smaller, larger, sum, difference, product, and ratio of these values and report them to the user.

Here is my code:

   cout << "Hello, please enter two integers: ";

   int val1;
   int val2;
   int garbage;

   cin >> val1 >> val2 >> garbage;

   cout << "Val1: " << val1
     << "\nVal2: " << val2
     << "\nGarbage: " << garbage << '\n';


   if (val1 < val2)
    cout << "\nval1 is smaller than val2.";

   if (val1 > val2)
    cout << "\nval1 is bigger than val2.";

   int sum = val1 + val2;
   int difference = val1 - val2;
   int product = val1 * val2;
   double ratio = 1.0 * val1 / val2;

   cout << "\nRatio: " << ratio
     << "\nSum: " << sum
     << "\nDifference: " << difference
     << "\nProduct: " << product << '\n';

Can somehow explain to me more in depth what is supposed to happen in this situation regarding what the operator >> and cin are doing behind the scenes, and why ratio becomes "inf" after i input the string "90.8 9" in my program?

Thank you.

Now what i have done instead of inputting straight ints is to input doubles to see what would happen. Now obviously i am aware that cin parses out values according to which type the second operand of the >> operator is. But what i have done is input the following string into the program: "90.8 and 9"

Somehow the ratio variable is output on the screen as "inf" and val2 is 0.

Val2 could be zero because of how >> operates, which is that if it detects a string when it is supposed to detect an int for an integer variable, >> adjusts the value of the second operand to 0. But i am not sure...

The "garbage" variable is just for me, i thought that cin did the following: See the value 90, input the value 90 in val1, see a string with the characters .8 and input 0 in val2, input 9 into garbage. But for some reason 9 is not being inputted in "garbage". Garbage is now a literal garbage value with a random integer inside of it.

Here's the output of my program:

Hello, please enter two integers: 90.8 9
Val1: 90
Val2: 0
Garbage: -858993460

val1 is bigger than val2.
Ratio: inf
Sum: 90
Difference: 90
Product: 0

Solution

  • In this line:

    cin >> val1 >> val2 >> garbage;
    

    When you enter 90.8 9, what happens in the following:

    1. operator>> tries to read an int value. It successfully parses 90 and stores that in val1.
    2. The next operator>> tries to parse another int value, but it encounters the . character. Hence, extraction of the int value fails and 0 is assigned to val2. operator>> puts std::cin into a fail state and no further extraction will happen on std::cin until you clear that state.
    3. cin does not attempt to extract any more because it is in a fail state. Hence the next operator>> will not assign 0 to garbage, hence garbage has an indeterminate value. You cannot read it or print it to the screen. Your code does it nevertheless, which means your code has undefined behavior, its output could be anything.

    This thing about assigning 0 was only introduced in C++11. And I still find it somewhat surprising that operator>> works like this when it fails in compound expressions. You can either check the state of cin after the extractions, and if any failed then assume that all of them failed.

    if (cin >> val1 >> val2 ) {
       // ok
    } else { 
       // either val1 and/or val2 were not successfully extracted
    }
    

    Or alternatively, use separate expressions for each extraction and check the failure state after each one:

    if (cin >> val1) {
        // successfully read 
        // val1 is safe to use 
    else {
        // handle failure
    }
    if (cin >> val2) {
       ...etc...
    

    Then, in this line:

    double ratio = 1.0 * val1 / val2;
    

    When val1 = 90 and val2 = 0, what happens is that 1.0 * val1 is evaluated first to yield a value of val1 but as a double. The line is basically the same as:

    double ration = static_cast<double>(val1) / val2;
    

    Hence the division uses floating-point division, not integer-division where division by 0 is undefined. Hence the result is inf.