Question

I have a problem, then given some input number n, we have to check whether the no is factorial of some other no or not.

INPUT 24, OUTPUT true
INPUT 25, OUTPUT false
I have written the following program for it:-

    int factorial(int num1) 
    {
        if(num1 > 1)
        {
           return num1* factorial(num1-1) ; 
        }
        else
        {
          return 1 ; 
        }
    }

    int is_factorial(int num2) 
    {
        int fact = 0  ; 
        int i = 0  ;
        while(fact < num2)
        {
             fact = factorial(i) ; 
             i++ ;
        }
        if(fact == num2)
        {
             return 0  ;
        }
        else
        {
             return -1;
        }
    }

Both these functions, seem to work correctly.
When we supply them for large inputs repeatedly, then the is_factorial will be repeatedly calling factorial which will be really a waste of time.
I have also tried maintaining a table for factorials

So, my question, is there some more efficient way to check whether a number is factorial or not?

Was it helpful?

Solution

It is wasteful calculating factorials continuously like that since you're duplicating the work done in x! when you do (x+1)!, (x+2)! and so on.


One approach is to maintain a list of factorials within a given range (such as all 64-bit unsigned factorials) and just compare it with that. Given how fast factorials increase in value, that list won't be very big. In fact, here's a C meta-program that actually generates the function for you:

#include <stdio.h>

int main (void) {
    unsigned long long last = 1ULL, current = 2ULL, mult = 2ULL;
    size_t szOut;

    puts ("int isFactorial (unsigned long long num) {");
    puts ("    static const unsigned long long arr[] = {");
    szOut = printf ("        %lluULL,", last);
    while (current / mult == last) {
        if (szOut > 50)
            szOut = printf ("\n       ") - 1;
        szOut += printf (" %lluULL,", current);
        last = current;
        current *= ++mult;
    }
    puts ("\n    };");
    puts ("    static const size_t len = sizeof (arr) / sizeof (*arr);");
    puts ("    for (size_t idx = 0; idx < len; idx++)");
    puts ("        if (arr[idx] == num)");
    puts ("            return 1;");
    puts ("    return 0;");
    puts ("}");

    return 0;
}

When you run that, you get the function:

int isFactorial (unsigned long long num) {
    static const unsigned long long arr[] = {
        1ULL, 2ULL, 6ULL, 24ULL, 120ULL, 720ULL, 5040ULL,
        40320ULL, 362880ULL, 3628800ULL, 39916800ULL,
        479001600ULL, 6227020800ULL, 87178291200ULL,
        1307674368000ULL, 20922789888000ULL, 355687428096000ULL,
        6402373705728000ULL, 121645100408832000ULL,
        2432902008176640000ULL,
    };
    static const size_t len = sizeof (arr) / sizeof (*arr);
    for (size_t idx = 0; idx < len; idx++)
        if (arr[idx] == num)
            return 1;
    return 0;
}

which is quite short and efficient, even for the 64-bit factorials.


If you're after a purely programmatic method (with no lookup tables), you can use the property that a factorial number is:

1 x 2 x 3 x 4 x ... x (n-1) x n

for some value of n.

Hence you can simply start dividing your test number by 2, then 3 then 4 and so on. One of two things will happen.

First, you may get a non-integral result in which case it wasn't a factorial.

Second, you may end up with 1 from the division, in which case it was a factorial.

Assuming your divisions are integral, the following code would be a good starting point:

int isFactorial (unsigned long long num) {
    unsigned long long currDiv = 2ULL;
    while (num != 1ULL) {
        if ((num % currDiv) != 0)
            return 0;
        num /= currDiv;
        currDiv++;
    }
    return 1;
}

However, for efficiency, the best option is probably the first one. Move the cost of calculation to the build phase rather than at runtime. This is a standard trick in cases where the cost of calculation is significant compared to a table lookup.

You could even make it even mode efficient by using a binary search of the lookup table but that's possibly not necessary given there are only twenty elements in it.

OTHER TIPS

If the number is a factorial, then its factors are 1..n for some n.

Assuming n is an integer variable, we can do the following :

int findFactNum(int test){
  for(int i=1, int sum=1; sum <= test; i++){
    sum *= i; //Increment factorial number
    if(sum == test)
        return i; //Factorial of i

   }
return 0; // factorial not found
}

now pass the number 24 to this function block and it should work. This function returns the number whose factorial you just passed.

You can speed up at least half of the cases by making a simple check if the number is odd or even (use %2). No odd number (barring 1) can be the factorial of any other number

#include<stdio.h>
main()
{
      float i,a;
      scanf("%f",&a);
      for(i=2;a>1;i++)
      a/=i;
      if(a==1)
      printf("it is a factorial");
      else
      printf("not a factorial");
}

You can create an array which contains factorial list:
like in the code below I created an array containing factorials up to 20. now you just have to input the number and check whether it is there in the array or not..

#include <stdio.h>
int main()
{
    int b[19];
    int i, j = 0;
    int k, l;

    /*writing factorials*/
    for (i = 0; i <= 19; i++) {
        k = i + 1;
        b[i] = factorial(k);
    }
    printf("enter a number\n");
    scanf("%d", &l);
    for (j = 0; j <= 19; j++) {
        if (l == b[j]) {
            printf("given number is a factorial of %d\n", j + 1);
        }
        if (j == 19 && l != b[j]) {
            printf("given number is not a factorial number\n");
        }
    }
}
int factorial(int a)
{
    int i;
    int facto = 1;
    for (i = 1; i <= a; i++) {
        facto = facto * i;
    }
    return facto;
}
public long generateFactorial(int num){
    if(num==0 || num==1){
        return 1;
    } else{
        return num*generateFactorial(num-1);
    }
}
public int getOriginalNum(long num){
    List<Integer> factors=new LinkedList<>();   //This is list of all factors of num
    List<Integer> factors2=new LinkedList<>();     //List of all Factorial factors for eg: (1,2,3,4,5) for 120 (=5!)
    int origin=1;               //number representing the root of Factorial value ( for eg origin=5 if num=120)
    for(int i=1;i<=num;i++){
        if(num%i==0){
            factors.add(i);     //it will add all factors of num including 1 and num
        }
    }

    /*
     * amoong "factors" we need to find  "Factorial factors for eg: (1,2,3,4,5) for 120"
     * for that create new list factors2
     * */
    for (int i=1;i<factors.size();i++) {         
        if((factors.get(i))-(factors.get(i-1))==1){   

            /*
             * 120 = 5! =5*4*3*2*1*1   (1!=1 and 0!=1 ..hence 2 times 1)
             * 720 = 6! =6*5*4*3*2*1*1
             * 5040 = 7! = 7*6*5*4*3*2*1*1
             * 3628800 = 10! =10*9*8*7*6*5*4*3*2*1*1  
             * ... and so on
             * 
             * in all cases any 2 succeding factors  inf list having diff=1
             * for eg: for 5 : (5-4=1)(4-3=1)(3-2=1)(2-1=1)(1-0=1)  Hence difference=1 in each case
             * */

            factors2.add(i);  //in such case add factors from 1st list " factors " to " factors2"
        } else break; 
        //else if(this diff>1) it is not factorial number hence break
        //Now last element in the list is largest num and ROOT of Factorial
    }
    for(Integer integer:factors2){
        System.out.print(" "+integer);
    }
    System.out.println();

    if(generateFactorial(factors2.get(factors2.size()-1))==num){   //last element is at  "factors2.size()-1"
        origin=factors2.get(factors2.size()-1);
    }
    return origin; 

    /*
     * Above logic works only for 5! but not other numbers ?? 
     * */
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top