0

I am kind of new to C++ and I am trying to write a recursive factorial calculator. I did write but it is giving multiple negative values for entries like 20, 21, 22, 33, 40, etc. And also the code fails to calculate factorial for integers greater than 65 despite my attempt to enable using long long int. Can someone please explain to me why this is happening? I didn't have any issue in python. Why is it happening in c++?

Here is my code:

#include "stdafx.h"
#include <iostream>
#include <conio.h>

using namespace std;

 long long int factorial(long int n) {
    long long int temp;
    if (n == 1 || n == 0) {
        return 1;
    }

    else {
        temp = n*factorial(n - 1);
        return temp;
    }
}

int main()
{
    int n, i;
    cout << "Enter positive integer or zero: ";
    cin >> n;

    while (n < 0 || cin.fail()) {
        cout << "\nFactorial cannot be calculated for n is negative." << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');

        cout << "Please try with integer >= 0: ";
        cin >> n;
    }

    cout << factorial(n) << endl;

    _getch();

    return 0;
}
Singiton
  • 31
  • 5

2 Answers2

2

It's simple overflow issue. You already know the result from python, so you can check if it's too big for the type you're using (obviously it is).

As for python, it has built-in support: Handling very large numbers in Python

Use a C++ bigint library.

Community
  • 1
  • 1
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • Thank you for the explanation but can we say the negation of value of really low integers like 21 is also related to stack overflow? This is the value I get for factorial of 21: -4249290049419214848 – Singiton Mar 19 '17 at 22:56
1

What you are experiencing is undefined behavior as a result of integer overflow. you are using a long long int which is a signed integer most likely to be represented as an 8 byte integer (this is platform specific).

Assuming from here one that your long long int is only 8 bytes(64 bits) that would mean that the maximum positive value that it can store is approximately 2^63 which is approx 9.223372037e+18.

Trying to calculate the factorial of numbers like 20, 21, 22, 33, 40, etc will result in a value larger than the maximum that a long long int can store which will result in undefined behavior which in this case is manifesting as integer wraparound.

To fix this you would need to use an integer data type capabale of representing larger values. I would start by switching to an unsigned long long int which will get you twice the range if numbers because an unsigned type deals only in positive numbers. That is just a band-aid on the issue though. To truly handle the problem you will need to find a library that does arbitrary precision integer math. (A bigint library)

(There are also some platform specific things you can do to ask your compiler for a 128bit int, but the better solution is to switch to a bigint data type)

EDIT:

I should clarify that by "bigint" i was not necessarily referring to any particular library. As suggested in the comments there are multiple options as to which library could be used to get the job done.

Alex Zywicki
  • 2,263
  • 1
  • 19
  • 34
  • Thank you very much! The negation issue solved by 'unsigned long long int'. But I have tried to include bigint library but it looks like the library is no longer supported. https://mattmccutchen.net/bigint/ I am using Visual studio 2015 and I don't see any library like 'bigint' – Singiton Mar 19 '17 at 23:20
  • 1
    @Singiton Use [boost::multprecision](http://ideone.com/thg02I). You can see more [here](http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/intro.html) – PaulMcKenzie Mar 19 '17 at 23:25
  • @Singiton keep in mind that using `unsigned long long int` did not solve your problem. You may not be seeing any negative numbers anymore but you will still be getting the undefined behavior I described above. You will still be attempting to calculate numbers larger than what can be stored in any built int integer type. – Alex Zywicki Mar 19 '17 at 23:37
  • @Alex I got your point thats why I provided I link to the resignation of bigint library. I will try boost::multprecision solution provided above. – Singiton Mar 20 '17 at 00:14
  • Installed [GNU GMP Library](https://gmplib.org/) as per [GNU GMP Manual](https://gmplib.org/manual/index.html#Top) and [boost library](http://www.boost.org/) then it worked. – Singiton Mar 26 '17 at 22:16