2

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;
}
im2shae
  • 57
  • 3
  • 12
  • 2
    What *should* the result be for `50`? What's the largest number that your homework needs to be able to calculate a factorial for? – Drew Dormann Jul 27 '15 at 16:31
  • 1
    The maximum value of an `int` is [`INT_MAX`](http://en.cppreference.com/w/cpp/types/climits) which is usually a little over two billion (on systems with 32-bit `int` which just about all normal systems). – Some programmer dude Jul 27 '15 at 16:35
  • It does not say a specific number. I have to use while statements and the type of variables I have learned so far : int, double/float, or bool. – im2shae Jul 27 '15 at 16:36

6 Answers6

9

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

yizzlez
  • 8,757
  • 4
  • 29
  • 44
  • 4
    Due to integer overflow... and the fact that 50! is divisible by 2^32. – Barry Jul 27 '15 at 16:33
  • i thought so. Thank you for clarifying that. I only learned the int, float or bool types. would it work better with a double/float type variable? – im2shae Jul 27 '15 at 16:33
  • 2
    @im2shae Note that 50! is far larger than even an unsigned long long, I would recommend a BigInteger class if you need precision. – yizzlez Jul 27 '15 at 16:34
  • thank you @awesomeyi. I think I would leave it at that since I'm not yet familiar with classes. It works up to 16 and I think the professor is looking more for the algorithm than big numbers. – im2shae Jul 27 '15 at 16:42
  • 1
    @im2shae A double _could_ work if you are not concerned with percision – yizzlez Jul 27 '15 at 16:43
  • 1
    @awesomeyi It does work. Although, a weird looking number but its not 0. I will bring in both solutions and see which one he wants. Thank you very much for all the help. – im2shae Jul 27 '15 at 16:51
  • @im2shae Try `#include ` and and do `std::to_string(factorial)` – yizzlez Jul 27 '15 at 16:52
  • 1
    It will work with a `double` but be very wrong as you are losing a lot of precision by multiplying an imprecise number many many times `(* 46 * 47 * 48 * 49 * etc)`. It's a good chance to learn but in the real world I prefer things that are obviously wrong (value of 0) over sneaky precision problems where I would need to actually double-check all 50 digits against an impressive calculator. – nvuono Jul 27 '15 at 16:55
  • 1
    @nvuono That is very true, which is why I only recommended a double to get the approximate result. – yizzlez Jul 27 '15 at 16:56
4

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

Community
  • 1
  • 1
gandgandi
  • 330
  • 1
  • 8
  • Thank you but I'm not yet familiar with classes. – im2shae Jul 27 '15 at 16:37
  • If you want to use c++, I recommend you to get familiar with them as fast as possible. In meantime you can write your own function that will handle big numbers. – gandgandi Jul 27 '15 at 16:42
2

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.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • 1
    +1, but 50 is quite a magic number and not portable because an `int`'s size varies among different systems. I guess the mathematically inclined could conjure about a portable assertion with `std::numeric_limits`. – Christian Hackl Jul 27 '15 at 17:29
  • @ChristianHackl yep, sure. I somehow "left it for the interested reader" to replace `50` with something more meaningful. Better magic than broken :P – 463035818_is_not_an_ai Jul 27 '15 at 17:41
1

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.

Bhavesh Kumar
  • 116
  • 1
  • 9
0

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

  • 1
    Double is obviously too small. Use some punctuation when writting your answers. – gandgandi Jul 27 '15 at 16:45
  • Sorry about my english. yes double is to small i think it is preferable to use class or a struct with multiple long long data type and modify the code accordingly – sambid shrestha Jul 27 '15 at 17:01
0

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.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62