About your solution, you are not rescuing the value of the function in a variable. It seems that you have an implicit idea in your code that the value of the variable resultado
is being changed on the recursion stack, but this does not occur.
Every variable in C is passed by value, not by reference (more on the subject). What is called reference passage in C is the passage of the variable pointer into the function. The address where the memory is stored is then modifiable. But, if you analyze how the pointer is passed, it itself is passed by value, making a copy of the pointer value into the function.
The first thing I decided to see is how fast the hyperfactor function grew. I found then this article in Mathworld, that led me to that OEIS sequence. I’ll put the values here n
, H(n)
and log2(H(n))
:
+---+---------------------+------------+
| n | H(n) | log2(H(n)) |
+---+---------------------+------------+
| 0 | 1 | 0 |
| 1 | 1 | 0 |
| 2 | 4 | 2 |
| 3 | 108 | 6.75 |
| 4 | 27648 | 14.8 |
| 5 | 86400000 | 26.4 |
| 6 | 4031078400000 | 41.9 |
| 7 | 3319766398771200000 | 61.5 |
+---+---------------------+------------+
This means that with the input argument 6
, we blew the storage capacity of a long int
(32 bits)!! With 7
we have reached the 64 bit storage capacity limit. I did not see the value for H(8)
, but it will surely blow and plenty the capacity of the long long int
.
Note that the amount of bits needed to store the information of a number n
any is floor(log2(x)) + 1
. Then we can transform the table above to accommodate the amount of bits:
+---+------------+---------+
| n | log2(H(n)) | bits(n) |
+---+------------+---------+
| 0 | 0 | 1 |
| 1 | 0 | 1 |
| 2 | 2 | 3 |
| 3 | 6.75 | 7 |
| 4 | 14.8 | 15 |
| 5 | 26.4 | 27 |
| 6 | 41.9 | 42 |
| 7 | 61.5 | 62 |
+---+------------+---------+
Assuming the question doesn’t want you to implement an integer with arbitrary capacity, then let’s go to a solution that respects the boundaries of the integer representation using only integer arithmetic.
The function hiperfatorial
is a pure function, therefore subject to memoization. I will define an error code -1
when trying to use a known number to give overflow numerical.
Also, internally I will need to use an entire potentiation function. I will start with it.
Naively, the whole potentiation function could be done so:
long long int int_pow_ingenuo(int base, int expoente) {
long long int resultado = 1;
int i;
for (i = 0; i < expoente; i++) {
resultado *= base;
}
return resultado;
}
This alternative is naive because it always does O(expoente)
multiplication operations. We can improve this alternative to run in o(lg(expoente))
multiplication operations.
The alternative to this is:
- split the exponent in two
- calculate this exponentiation with that half of the exponent
- multiply the previous result by itself
- if the exponent is odd, multiply the previous result by the base
I will take the values as the basis of the recursion:
0
: always returns 1
1
: returns the base value
2
: returns the base value multiplied by itself
It would look like this exponentiation:
long long int int_pow(int base, int expoente) {
long long int resultado_parcial;
switch (expoente) {
case 0:
return 1;
case 1:
return base;
case 2:
return base * base;
}
resulta_parcial = int_pow(base, expoente/2);
if (expoente % 2 == 1) {
return resulta_parcial * resulta_parcial * base;
} else {
return resulta_parcial * resulta_parcial;
}
}
Note that int_pow
is also a pure function, but as it is only used internally, it is not interesting to me.
Now, the code for hiperfatorial
. The first step are the basic cases:
The other cases will be made through the memoization. I will call the memoization vector of this function memo_hiperfatorial
. As only the values in the range are interested [0, 7]
and the basic case is hiperfatorial(0) = 1
, let’s start the vector with zero values for all cases, except memo_hiperfatorial[0]
, worthwhile 1
. The boot I chose is like this:
static long long int memo_hiperfatorial[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
I put the variable as static to isolate it. I thought initially for her on the compilation drive, but being static she can quietly stay in function.
Advancing a little further in the writing of the function, we can assume that previously memoised values can already be returned immediately. A value is identified as memoized case memo_hiperfatorial[n] != 0
(for the context of this response, there are other alternatives with other strategies).
long long int hiperfatorial(int n) {
static long long int memo_hiperfatorial[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
if (n >= 8 || n < 0) {
return -1;
}
if (memo_hiperfatorial[n] != 0) {
return memo_hiperfatorial[n];
}
...
}
Okay, now all that’s left is the recursion-favoring step to reach the next value. By definition, hyperfactorial can be escite like this:
Then the recursive step would be:
return int_pow(n, n) * hiperfatorial(n - 1);
To update the memoised values:
return memo_hiperfatorial[n] = int_pow(n, n) * hiperfatorial(n - 1);
Therefore, putting it all together (and re-capitulating int_pow
):
long long int int_pow(int base, int expoente) {
long long int resultado_parcial;
switch (expoente) {
case 0:
return 1;
case 1:
return base;
case 2:
return base * base;
}
resulta_parcial = int_pow(base, expoente/2);
if (expoente % 2 == 1) {
return resulta_parcial * resulta_parcial * base;
} else {
return resulta_parcial * resulta_parcial;
}
}
long long int hiperfatorial(int n) {
static long long int memo_hiperfatorial[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
if (n >= 8 || n < 0) {
return -1;
}
if (memo_hiperfatorial[n] != 0) {
return memo_hiperfatorial[n];
}
return memo_hiperfatorial[n] = int_pow(n, n) * hiperfatorial(n - 1);
}
What is the definition of "hyperfactor"?
– Jefferson Quesado
How much should I give if I entered 5 for example?
– Maniero
For some reason I can’t make the symbols squared and cube on this keyboard so I had to make this mess of parentheses.
– Bruno Lobo
Seria
H(n) = 1² * 2² * 3² * 4² * ... * n²
?– Woss
No Anderson, it would be every number having as exponential itself
– Bruno Lobo
So your previous notation went a long way from that. It’s defined as hyperfactor by
H(n)
, beingH(n) = 1^1 * 2^2 * 3^3 * 4^4 * ... * n^n
.– Woss
What I don’t understand is where exactly is an error that the multiplication value is not being passed to the result
– Bruno Lobo
Oops, truth, my mistake!
– Bruno Lobo
Problem 8. The hyperfactor of a number n, denoted H(n) is calculated as follows: H(n) = (1 1).(2).(3 3).(....). ((n 1) (n 1)).(n n) Make a recursive function that takes an integer n and returns the hyperfactor of that number
– Bruno Lobo
If the number entered was 5 then the answer was to be 86.400.000 I think
– Bruno Lobo