简体   繁体   中英

Simple C++ factorial program

as homework I need a program that reads a nonnegative integer and computes and prints its factorial. So far I wrote the code but if I try to input 50! the result is 0. It works with smaller numbers. Any help would be much appreciated.

#include <iostream>

using namespace std;

int main()
{
    int counter = 1;
    int number;

    cout << "Please enter a number: ";
    cin >> number;

    int factorial = number;
    while (counter != number)
    {
        factorial = factorial * (number - counter);
        counter++;

    }

    cout << "The factorial of " << number << "! is: " << factorial << endl;
    return 0;
}

50! is 30414093201713378043612608166064768844377641568960512000000000000 , far too large for an int. Due to integer overflow, the result is 0.

If you want to compute big factorials you need to use some BigInteger class. Look at this: Thread

There are already some answers. However, they all lack to provide some (imho) important fact:

No matter how big you choose the type of the result, there is always a limit on what your program will be able to compute.

On normal pocket calculators 69! is the biggest factorial they can display (because it is the biggest one with two digits exponent). Asking for anything bigger will simply result in an error or NaN. Actually this is perfectly fine, because in practice your rarely need such huge factorials with perfect precision. Often one can either use Stirlings approximation or use other tricks to avoid lengthy calculations (btw 69! is also a nice benchmark for pocket calculators, because it can take already up to seconds on slower ones).

Conclusion : Your code is perfectly fine for reasonable input. If you really needed to go for higher factorials, there are ways, but I suppose your assignment does not really ask for it. Moreover, no matter how you do it, you always hit a limit. Thus to make your code "bug free" I would add something like an

assert(number < 50 && "Sorry, this number is too big");

before the calculation.

Choose your data type of larger range that won't exceed the value stored in variable 'factorial'

You should declare it as , **long long int factorial = number ;**

Now , it shows zero because int (here signed) so it has range from -32568 to +32567 for a system which store int data type as 2byte. And with the help of modifier "long long" you actually increasing its storage bytes to 8bytes which results in larger range.

Now, if value to be store in any variable exceeds its range then it performs a cyclic rotation by beginning the value to be stored from least range (here it is -32568).

And you can also use , **unsigned long long int factorial = number ;** to even make it of much larger range. As unsigned will count its negative range with positive range which results in much larger positive range.

Try double or long data types in a class or struct. You also have to modify your code accordingly.

Factorial just produces insanely big numbers. You can try with wider or possibly wider data types (like long ), but this will only postpone the problem. It will fail at some point. Perhaps at 51! , perhaps at 60! . And let's not even talk about 1000! . That's the nature of factorial.

Specialised libraries for big numbers can greatly mitigate the problem, of course. But they are not beginners' stuff.

What you can very well do, however, is to find out safely if your program hits your computer's limit, and print an error message if that's the case. C++ provides a mechanism called std::numeric_limits which tells you the biggest possible value a data type can represent.

Here is a simple example based on your code:

#include <iostream>
#include <limits> // needed for std::numeric_limits

using namespace std;

int main()
{
    int counter = 1;
    int number;

    cout << "Please enter a number: ";
    cin >> number;

    int factorial = number;
    while (counter != number)
    {
        if (std::numeric_limits<int>::max() / factorial < (number - counter)) {
            std::cout << "cannot handle such large numbers\n";
            return 0;
        }       
        factorial = factorial * (number - counter);
        counter++;

    }

    cout << "The factorial of " << number << "! is: " << factorial << endl;
    return 0;
}

What will happen once the error condition has been detected is not important here, but rather how you detect it:

std::numeric_limits<int>::max() / factorial < (number - counter)

This prevents integer overflows. It is mathematically equivalent to:

std::numeric_limits<int>::max() < factorial * (number - counter) // wrong!

However, the latter version obviously does not work, because factorial * (number - counter) may already produce an overflow. By turning the multiplication on the right into a division on the left, you elegantly avoid the problem.


By the way, all of this will still do no good if the user enters a very big number. You should therefore check the status of std::cin before using number , and likewise print an error message if the input could not be interpreted as an int . That makes your program more robust. It will not simply crash or produce nonsense results if someone enters big numbers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM