recursive superfatorial problem

4

I'm having a question about how to do this recursive math function.

Calculation of the superfatorial:

The super-factorial of an N number is defined by the product of the first N factorials Thus, the superfatorial of 4 is sf (4) = 1! * 2! * 3! * 4! = 288 Make a recursive function that receives a positive integer N and returns the super-key of that number.

My code:

int super (int n, int m) {
   if (m == 1) return 1;
   if (n == 1) return super (m - 1, m - 1);
   return n * super(n - 1, m);
}

When calling the function, super (n, n), the value of the superfactor of n is returned correctly. Notice that I used two parameters, n and m. The parameter m is used to perform the function. This is my question, because in the question it asks for only one parameter (n). I could not think of a way to do it with a super param (n). Is it possible?

Thank you in advance.

    
asked by anonymous 07.09.2015 / 17:11

4 answers

1

This may not be so relevant in this case (because the factorial value - and consequently the superfactor value - grows so fast that it is unfeasible to calculate it for large numbers), but how you and the other respondents are calculating has a inefficiency, which is to calculate again and again components used in various parts of the calculation (as pointed out by user2856432). When calculating 4! for example you already calculate 3! , best to use this result after calculating 3! again in the next term. The complexity in the case is quadratic with the value of the argument.

I will show an alternative here, not so much by the problem itself (which as I said, it is not feasible to do for large numbers) but to demonstrate a very useful technique when working with recursion - the accumulator :

int sfat(n) {
    return sfat2(1, n, 1); // Vai de 1 a n, e o valor acumulado é 1
}

int sfat2(inicio, fim, acumulador) {
    if ( inicio > fim )
        return acumulador;
    return acumulador * sfat2(inicio+1, fim, inicio*acumulador);
}

Explaining, if it is not clear what the code is doing:

  • The initial call passes 0! = 1 as accumulator, and the range goes from 1 to n ;
  • The first call - term 1 - multiplies this (n-1)! = (1-1)! = 0! by the result of the recursive call, which in turn receives as n*(n-1)! = 1*(1-1)! = 1*0! = 1! accumulator;
    • The result is 0! * sfat(1)
  • The second call - term 2 - multiplies this (n-1)! = (2-1)! = 1! by the result of the recursive call, which in turn receives n*(n-1)! = 2*(2-1)! = 2*1! = 2! as accumulator;
    • The result is 0! * 1! * sfat(2)
  • The third call - term 3 - multiplies this (n-1)! = (3-1)! = 2! by the result of the recursive call, which in turn receives as n*(n-1)! = 3*(3-1)! = 3*2! = 3! accumulator;
    • The result is 0! * 1! * 2! * sfat(2)
  • ...
  • The nth call - term n - multiplies this (n-1)! by the result of the recursive call, which in turn receives as accumulator n*(n-1)! ;
    • The result is 0! * 1! * 2! * ... * (n-1)! * sfat(n+1)
  • The next call - term n+1 - finds the stop condition, returning the accumulator ((n+1) - 1)! = n! ;
    • The result is 0! * 1! * 2! * ... * (n-1)! * n!

As you can see, the number of recursive calls is now linear with the value of the argument.

Note : If you wanted to implement tail recursion - where the recursive call is the last executed operation (useful in languages whose compiler optimizes this type of call, transforming it into iterative) - you could do this through two accumulators: one for the factorial, and another for result:

int sfat(n) {
    return sfat2(1, n, 1, 1); // Acumula (n-1)! e o resultado
}

int sfat2(inicio, fim, fat_acc, sfat_acc) {
    if ( inicio > fim )
        return sfat_acc;
    return sfat2(inicio+1, fim, inicio*fat_acc, inicio*fat_acc*sfat_acc);
}

Examples in ideone .

    
02.10.2015 / 01:32
4

Hello, I would solve by creating an additional function, without changing anything of the one you posted. It's basically what you yourself said, just do not do that on main, there would be called superfat, which has only one parameter.

int super (int n, int m) {
   if (m == 1){
        return 1;
   }
   if (n == 1){
        return super (m - 1, m - 1);
   }
   return n * super(n - 1, m);
}

int superfat (int n){
    return super(n, n);
}

int main(){

    printf("%d", superfat(4)); //288

    return(0);
}
    
09.09.2015 / 15:55
3

An alternative is to use a factorial function (n), so the super (n) function becomes recursive without an auxiliary function:

#include <stdio.h>

int fact(n) {
    if(n == 0) {
        return 1;
    }

    //return n*fact(n-1); /* descomentar aqui se preferir definição recursiva (pior performance) /*

    int result = 1;
    while (n > 0) {
        result = n*result;
        n--;
    }
    return result;
}

int super(n) {
    if(n == 0) {
        return 1;
    }
    return fact(n)*super(n-1);
}

int main() {
    printf("Result fact(%d): %d\n", 4, super(4));
    return 0;
}

Remember that this implementation is not optimal, since every recursion of super () several factorials that have already been calculated before are recalculated. (For a real problem involving factorial I imagine the most efficient is to have a set of same tabulated values).

But for your question this answer is enough.

    
10.09.2015 / 19:11
1

Pretty much what user2856432 said only in a more compact way:

int fat(int val){
       if(!val) return 1;
       else return val * fat(val-1);       
}

int sfat(int val){
       if(!val) return 1;
       else return fat(val) * sfat(val-1);
}
    
10.09.2015 / 22:07