Factorial help

so im making a program that gets factorials of numbers and returns them and using catch and throw to handle what happens when the numbers overflow into negative.
im trying to do this however the numbers over flow at 13 but im not catching it until 17 can anyone tell why?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <iomanip>
#include <cstdlib>

using namespace std;


int factorial(int n)
{
    int tmp;
  
    if(n == 0)
       return 0;
    if (n == 1)
    
       return 1;
        
    tmp = n * (factorial(n - 1));
    
       
      try{ 
      if(tmp<0)
       throw(tmp);
       }
       catch (int tmp)
        {
              cerr << "Overflow at tmp = " << tmp << endl;
              
              }
              
    return tmp;
}

int main()
{
    

for(int i=0;i<20;i++)
{
        
        cout << "Calculating: " << i << endl;
 
            //if(factorial(i)<0)
                //throw(i);
              
              cout << factorial(i) << endl;
              cout<<endl;
              }
              
}

i tried moving the try statement before the tmp = ... and it only makes it to 11
Last edited on
There is no point in using exceptions here if you are going to catch them immediately. It could be that 13! and 14! are actually positive because some large number x 13 x 12 ... loops around enough times to get back to a positive number.
the reason for using exception is because my professor says we must use them, its just to teach us how to use them. and im pretty sure thats what it is doing how can i fix that?
here is the output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Calculating: 0
0

Calculating: 1
1

Calculating: 2
2

Calculating: 3
6

Calculating: 4
24

Calculating: 5
120

Calculating: 6
720

Calculating: 7
5040

Calculating: 8
40320

Calculating: 9
362880

Calculating: 10
3628800

Calculating: 11
39916800

Calculating: 12
479001600

Calculating: 13
1932053504

Calculating: 14
1278945280

Calculating: 15
2004310016

Calculating: 16
2004189184

Calculating: 17
-288522240

Calculating: 18
-898433024

Calculating: 19
109641728

.

as you can see 13 is not negative but 13 is larger then 14 and so is 15 and 16 so there is some wrapping going on
You'll have to *gulp* manually do multiplication via manual addition via adding 1 over and over...and over...and checking that the value is not going to go past 4294967295
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//what about "inverse logic"?
if( std::numeric_limits<int>::max()/n < factorial(n-1) )
  throw n;

//main
for(int K=0; K<n; ++K){
  try{
    std::cout << K << ' ' << factorial(K) << std::endl;
  }
  catch(int x){
    std::cerr << "Overflow at " << x;
    break;
  }
}
would making it a long it work?

tried making it a long int and does the same problem, ne555 could you explain what you said does?
Last edited on
it depends of the 16 bits,32 bits, etc.. numbers not the code i think.. :-)
std::numeric_limits<int>::max() That is the biggest int.
By using the inverse operation it calculates the biggest number that will not overflow.
you can use long long int or unsigned long long int :)
so ive tried changing it to unsigned and long and long long and i still get the same problem, as for what ne555 said i get what your saying but im not sure how to use what your saying, im sorry if my lack of understanding frustrates you i just want to make sure i understand it completely before i use it so when i do my lab write up i can explain it in detail why i used it.

here is my code as of now, it now stopes at 14 rather then 17 however the factorial it returns for 13 is still wrong it returns

Calculating: 13
1932053504

where 13 should be 6227020800 which is larger then a 32 bit number can go but it doesnt change when i make it long or long long or anything, i really dont even understand why its wrapping arround rather then going negative.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <iomanip>
#include <cstdlib>

using namespace std;


int factorial(int n)
{
    int tmp;
  
    if(n == 1)
       return 1;          
        
    tmp = n * (factorial(n - 1));
    
       try{ 
      if(tmp<0)
       throw(tmp);
       }
       catch (int tmp)
        {
              cerr << "Overflow at tmp = " << tmp << endl;
              
              }
    
    return tmp;
}

int main()
{   
    cout<<"Calculating: 0"<<endl;
    cout<<factorial(1)<<endl;
    cout<<endl;
    cout<<"Calculating: 1"<<endl;
    cout<<factorial(1)<<endl;
    cout<<endl;
for(int i=2;i<20;i++)
{
        
        cout << "Calculating: " << i << endl;
 
            
             try{
                  if(factorial(i)<factorial(i-1))
                      throw(i);
                      }
                      catch (int i)
                      {
                            cerr << "The number has wrapped around and overflowed at " << i << endl;
                            
                             }
              
              cout << factorial(i) << endl;
              cout<<endl;
              }
              
}

Last edited on
1
2
    cout<<"Calculating: 0"<<endl;
    cout<<factorial(1)<<endl;
That is cheating. Modify your factorial function to accept 0 as an input. (you may want to handle negative numbers, too)

tmp = n * (factorial(n - 1)); The problem here is that the if the overflow occurs you don't see it.

i really dont even understand why its wrapping arround rather then going negative.
Suppose a 1 byte number. The maximum positive is 127, minimum negative -128, total numbers 256.
Now you do 100*4 this give you 400, overflows, so is taken module 256.
400%256 = 144, which is a positive number! and bigger than the one you have before.
So all comes to the false assumption that when overflows, the number turns out negative (or less that its previous value).
Just to clarify, that was just an example of how the information was presented. I don't know what the system does in case of overflow (the module 256 could be wrong).

1
2
3
4
int tmp = factorial(n-1); //this is "safe" (if it wasn't, an exception was throw before)
if( std::numeric_limits<int>::max()/n < tmp ) //checking if the operation will fail
  throw n;
return n*tmp; //performing the operation 


About exceptions.
An error occurs, you don't know how to handle it.
Then you derive it to your supervisor that will know what to do (or will derive it to other)
If you can handle the error right where occurs, then you don't need exceptions.

Consider your factorial function.
You detect an overflow, put an error message, but then you give an incorrect value to the caller.
And the caller doesn't know that the value is incorrect.
Last edited on
ne555 seems to have answered the question--just for the record, 0!=1.
Thank you ne555 for taking the time to explain it more i understand what going on now and took your advice and it fixed what was happening, your help is much obliged.
Topic archived. No new replies allowed.