4

I was working on a little program that would take a number as input, check if it's bigger than the variable largest and check if it's smaller than the variable smallest. Those variables were supposed to keep track of, well, the largest and smallest value entered so far.

The only problem is that both values start off holding garbage values, so I tried to assign both to zero, but when I do so the program breaks, because when I enter five for example it's supposed to be largest and smallest value but instead C++ assigns zero to the smallest value.

#include<iostream>

int main() {
    double a, largest, smallest;
    while (std::cin >> a) { 
        if (largest < a)
            largest = a;
         if (smallest > a)
            smallest = a;

        std::cout << "The smallest so far: " << smallest <<'\n';
        std::cout << "The largest so far: " << largest << '\n';
    }
}
Saten-san
  • 55
  • 5

4 Answers4

10

The simplest approach would be to set smallest to the largest possible value, and largest to the smallest possible value:

double largest = std::numeric_limits<double>::lowest();
double smallest = std::numeric_limits<double>::max();

If you actually want to make a variable have no value, that's what std::optional is for. std::optional<double> largest; would be initialized to have no value at all.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
2

With std::optional. https://en.cppreference.com/w/cpp/utility/optional The std::optional can have, or not, a value. At start, it hasn't value. You can use it to handle the state "don't have yet a value assigned"

Here an example with your case :

#include<iostream>
#include <optional>

int main() {
    double a;
    std::optional<double> largest, smallest;
    while (std::cin >> a) {
        if (largest.has_value() == false || largest < a)
            largest = a;
        if (smallest.has_value() == false || smallest > a)
            smallest = a;

        std::cout << "The smallest so far: " << smallest.value() << '\n';
        std::cout << "The largest so far: " << largest.value() << '\n';
    }
}
MatthieuL
  • 514
  • 1
  • 3
  • 7
  • 3
    @Evg 1) yes, but I prefered wrote .has_value() == false to be more understable by the author. 2) no need for the * in the < or > : `template< class T, class U > constexpr bool operator>( const optional& opt, const U& value );` https://en.cppreference.com/w/cpp/utility/optional/operator_cmp – MatthieuL Jun 13 '20 at 13:33
1

With a subtle (but significant) change in the two comparisons, one could initialize largest and smallest to NaN (not-a-number) values and then take advantage of the fact that all comparisons to NaN values return false:

#include <iostream>
#include <cmath>

int main()
{
    double a, largest = std::nan(""), smallest = std::nan("");
    while (std::cin >> a) {
        if (!(a <= largest))
            largest = a;
        if (!(a >= smallest))
            smallest = a;

        std::cout << "The smallest so far: " << smallest << '\n';
        std::cout << "The largest so far: " << largest << '\n';
    }
    return 0;
}

This is not really a significant improvement on the answer provided by cdhowie, but I'm nonetheless offering it as an alternative approach.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
1

The reason for the behaviour you see is that largest and smallest are uninitialised, and then their values are accessed in the tests (if largest < a) and if (smallest > a) respectively. Accessing their values (which is necessary in any comparison) then causes undefined behaviour.

One fix is to ensure their values are initialised before the first attempt to access their values.

if (std::cin >> a)
{
    smallest = largest = a;

    do
    { 
        if (largest < a)      // Safe since variables are initialised
           largest = a;
        else if (smallest > a)
           smallest = a;
        std::cout << "The smallest so far: " << smallest <<'\n';
        std::cout << "The largest so far: " << largest << '\n';
    }  while (std::cin >> a);
}
Peter
  • 35,646
  • 4
  • 32
  • 74