Reputation: 57
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;
}
Upvotes: 2
Views: 8180
Reputation: 27528
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.
Upvotes: 0
Reputation: 122516
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.
Upvotes: 2
Reputation: 99
Try double or long data types in a class or struct. You also have to modify your code accordingly.
Upvotes: 0
Reputation: 116
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.
Upvotes: 1
Reputation: 330
If you want to compute big factorials you need to use some BigInteger class. Look at this: Thread
Upvotes: 4
Reputation: 8805
50!
is 30414093201713378043612608166064768844377641568960512000000000000
, far too large for an int. Due to integer overflow, the result is 0.
Upvotes: 9