Search code examples
c++intinteger-overflow

Prevent a user from entering a value which would cause integer to overflow


I'm very new to C++ programming, and have written a simple program to calculate the factorial of an integer provided by the user. I am attempting to account for inputs which would cause an error, or do not make sense (e.g. I have accounted for input of a negative number/-1 already). I want to print out an error if the user enters a number whose factorial would be larger than the maximum integer size.

I started with:

if(factorial(n) > INT_MAX)
std::cout << "nope";
continue

I tested this with n = ~25 or 26 but it doesn't prevent the result from overflowing and printing out a large negative number instead.

Second, I tried assigning this to a variable using a function from the 'limits.h' header and then comparing the result of factorial(n) against this. Still no luck (you can see this solution in the code sample below).

I could of course assign the result to a long and test against that but you wouldn't have to go very far until you started to wrap around that value, either. I'd prefer to find a way to simply prevent the value from being printed if this happens.

#include <iostream>
#include <cstdlib>
#include <limits>

int factorial(int n)
{
    auto total = 1;

    for(auto i = 1; i <= n; i++)
    {
        total = total * i;      //Product of all numbers up to n
    } 
    return total;
}

int main()
{
    auto input_toggle = true;
    auto n = 0;
    auto int_max_size = std::numeric_limits<int>::max();

    while(input_toggle = true)
    {
    /* get user input, check it is an integer */
            if (factorial(n) > int_max_size)
        {
            std::cout << "Error - Sorry, factorial of " << n << " is larger than \nthe maximum integer size supported by this system. " << std::endl;
            continue;
        }

        /* else std::cout << factorial(n) << std::endl; */`

As with my other condition(s), I expect it to simply print out that small error message and then continue asking the user for input to calculate. The code does work, it just continues to print values that have wrapped around if I request the factorial of a value >25 or so. I feel this kind of error-checking will be quite useful.

Thanks!


Solution

  • You are trying to do things backwards.

    First, no integer can actually be bigger than INT_MAX, by definition - this is a maximum value integer can be! So your condition factorial(n) > int_max_size is always going to be false.

    Moreover, there is a logical flaw in your approach. You calculate the value first and than check if it is less than maximum value allowed. By that time it is too late! You have already calculated the value and went through any overflows you might have encountered. Any check you might be performing should be performed while you are still doing your calculations.

    In essence, you need to check if multiplying X by Z will be within allowed range without actually doing the multiplication (unfortunately, C++ is very strict in leaving signed integer overflow undefined behavior, so you can't try and see.).

    So how do you check if X * Y will be lesser than Z? One approach would be to divide Z by Y before engaging in calculation. If you end up with the number which is lesser than X, you know that multiplying X by Y will result in overflow.

    I believe, you know have enough information to code the solution yourself.