How to check whether a no is factorial or not?

旧时模样 提交于 2019-12-22 08:17:14

问题


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?


回答1:


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.




回答2:


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.




回答3:


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




回答4:


#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");
}



回答5:


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;
}



回答6:


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 ?? 
     * */
}


来源:https://stackoverflow.com/questions/21200118/how-to-check-whether-a-no-is-factorial-or-not

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!