What is the magic behind that recursive function? - c

Question:
Can you explain me how that fuction returns the correct result 16?
I am new to programming and now this code is recursive, however I think I am getting lost as much as I think I understand them. Even though, I believe I figure out factorial recursions or fibonacci ones.
The base is 0, that's good, but I can't figure out why I get 16... I printed every variable inside the function and dubugged, but those did not help more than troubling. When b variable is 0 (and a variable is 32) the condition is met, but why it returns value 16? I would understand a kind of function as n * fact(n-1) as in a classic factorial fuction example, but here I can't visualize how the recursion returns the expected result.
Code:
#include <stdio.h>
int fun(int a, int b)
{
if (b == 0)
{
return 0;
}
if (b % 2 == 0)
{
return fun(a+a, b/2);
}
return fun(a+a, b/2)+a;
}
int main()
{
printf("%d\n", fun(4, 4));
return 0;
}
Thanks in advance!

Add printouts and it will become very clear:
int fun(int a, int b)
{
printf("fun(%d, %d)\n", a, b);
if (b == 0) {
printf("b == 0, returning 0\n");
return 0;
}
if (b % 2 == 0) {
printf("b is even, returning f(%d, %d)\n", a+a, b/2);
return fun(a+a, b/2);
}
printf("b is odd, returning f(%d, %d) + %d\n", a+a, b/2, a);
return fun(a+a, b/2)+a;
}
Output:
$ ./a.out
fun(4, 4)
b is even, returning f(8, 2)
fun(8, 2)
b is even, returning f(16, 1)
fun(16, 1)
b is odd, returning f(32, 0) + 16
fun(32, 0)
b == 0, returning 0
16
So what happens in the end is that f(16, 1) will return f(32, 0) + 16 and f(32, 0) evaluates to zero, so 16 is returned.
You could also do like this, but do note that this will alter the order of the outputs because the printout need to wait for the return:
int fun(int a, int b)
{
printf("fun(%d, %d)\n", a, b);
if (b == 0) {
printf("b == 0, returning 0\n");
return 0;
}
if (b % 2 == 0) {
int ret = fun(a+a, b/2);
printf("b is even, returning f(%d, %d) = %d \n", a+a, b/2, ret);
return ret; //fun(a+a, b/2);
}
int ret = fun(a+a, b/2) + a;
printf("b is odd, returning f(%d, %d) + %d = %d \n", a+a, b/2, a, ret);
return ret;
}
Output:
$ ./a.out
fun(4, 4)
fun(8, 2)
fun(16, 1)
fun(32, 0)
b == 0, returning 0
b is odd, returning f(32, 0) + 16 = 16
b is even, returning f(16, 1) = 16
b is even, returning f(8, 2) = 16
16
A good way to understand recursion is to use pen and paper to see why the order of printouts is so different in these cases. But I leave that to you.

I find helpful to think about these kind of recursive functions as mathematical tools. What I mean is that a recursive function works if:
It always says the truth.
You can prove that it ends, eventually.
You don't say, but I guess that your function fun(a, b) does a multiplication a * b. And it does it by reducing it:
If b==0 then a * b -> 0
Else, if b is even then a * b -> (a+a) * (b/2).
Else (b is odd), a * b -> ((a+a) * (b/2)) + a
These equations are trivially true, as long as b >= 0 of course, which I assume that is a precondition of your function.
You also can see that it will eventually finish, as the value of b gets smaller and smaller, and it will always reach 0 at the end.
That should be enough to believe that your function works. If you want to trace each intermediate step, you can check your truth every time to ensure that you doing it properly.
a=4, b=4, b is even, so foo(4,4) -> foo(8, 2) (we know that 4*4 == 16, and 8*2 == 16 too, so we are on the right track).
a=8, b=2, b is even, so foo(8, 2) -> foo(16, 1) (16 * 1 ==16, we are still ok).
a=16, b=1, b is odd, so foo(16, 1) -> foo(32, 0) + 16. Here is the tricky part, this call is not tail-recursive, there is the latter addition. But still, 32*0 + 16 = 16 so we are on the right track.
a=32, b=0 b is 0 so it returns 0 (ok, because 32*0 = 0).
Then there is the latter sum: 0 + 16 = 16 and that value is returned all up to main.

There are two things about recursive functions:
recursive functions are not special. Eg. they work the same way as if you called a different function that served the same purpose for the smaller sub problems.
All functions will have their own arguments and local variables. The location of a and b is new for each invocation of a fucntion. Thus if you call the same function from itself there will be no interference between the two!
You should do substitution rules:
Replace the call with the code that is executed according to the conditionals.
Repeat until you no longer have anything to call
Example:
fun(4, 4) // initial call
fun(4+4, 4/2) // because 4 % 2 == 0
fun(8+8, 2/2) // because 2 % 2 == 0
fun(16+16, 1/2) + 16 // because 1 % 2 != 0.
0 + 16 // because 1/2 == 0 and then b == 0
16 // because 0 + 16 == 16

Related

How to find out whether two numbers are powers of the same number and those powers

So say you are given the numbers 27 and 81. How would a program that tells you that the 4th root of 81 is 3 and the cubic root of 27 is three. (Both have the root of 3).
x = 16;
y = 4;
foo = same_root(16, 4); // foo = 2
root1 = find_root(16, 2); // root1 = 4
root2 = find_root(4, 2); // root2 = 2
For CommonRoot(a,b),
you say x'th root of a = y'th root of b,
which is the same as a^(1/x) = b^(1/y)
So isolating y :
//log_x is log base x
log_b(a^(1/x)) = 1/y
(1/x)log_b(a) = 1/y
x/log_b(a) = y
//Or
x/(log(a)/log(b)) = y
This function will take in entry x, which is the x of x'th root of a and return the corresponding y of y'th root of b. By doing a^(1/x) or b^(1/y), you find the common root.
So you can iterate through the values of x, waiting to get an integer y and if you do b^(1/y), you will get a common root. To be mentionned also, this method helps you finding multiple common roots and non-integer common roots.
So here's a pseudo-code example :
CommonRoot(float a, float b){
For(int x = 0; x < max(a,b); x++){ // max(a,b) is just to set a threshold of search,
//I haven't actually tested this, so I don't know what would be a good threshold
float y = x/(log(a)/log(b)); // gather a y for an x
If ( fPart(y) == 0){ // test if y is an integer
If( fPart(b^(1/y)) == 0){ // the answer might lead to a non-integer common root (such as 1.4 beeing a common root of 1.4^2 and 1.4^5)
return b^(1/y); //return the common root
}
}
}
return -1; //if it hasn't found anything, return -1 or error.
}
Please note that this algorithm will likely return the highest common root, not the lowest.
I had a lot of fun finding an optimized solution for you, I hope I helped :).
You can utilize that simple fact that powers of the same number are divisible by each other. And the product itself is a power of the same root. It means that we can have a simple recursive algorithm as follows:
Check if the smaller number divides the larger one.
If not - return false (-1 in the code below)
If yes, recursively repeat for the smaller number and the product
Our stopping conditions should be when both numbers are equal, but neither is 1, because 1 can't be a common root.
Here is C code implementing this idea (for positive numbers):
#include <stdio.h>
#define TEST(x, y) printf("%d, %d => %d\n", (x), (y), common_root((x),(y)))
int common_root(int a, int b)
{
int temp;
if (a == 1 || b == 1)
return -1;
if (a == b) {
return a;
}
if (a > b) {
// Swap to make sure a < b
temp = a;
a = b;
b = temp;
}
if ( (b % a) == 0) // Check if `b` divisible by `a`
return common_root(a, b/a);
else
return -1;
}
int main(void) {
TEST(1,2);
TEST(2,3);
TEST(6,10);
TEST(4, 16);
TEST(12, 24);
TEST(27, 81);
return 0;
}
Output:
1, 2 => -1
2, 3 => -1
6, 10 => -1
4, 16 => 4
12, 24 => -1
27, 81 => 3
Demo

How to multiply and print the digits of 2 numbers recursively

I'm looking for a way to multiply the digits of two numbers (not necessarily of the same digits length) recursively without using loops in the following way:
let's say the numbers are 123 and 567. I'm trying to figure out a way to print:
5
6
7
10
12
14
15
18
21
it's the left most digit of the first number times every digit of the second number starting from the left and moving in both the right most.
the function must fit the prototype:
void multi(int a, int b);
I've managed to dive recursively to 1 and 5 from there to 1 56 and then 1 567 and in every call I print the result of a%10 * b%10.
but when backtracking to 12 567 the function dives to 1 567 again.
here's my best attempt:
int main()
{
int a, b;
scanf("%d %d", &a, &b);
multi(a, b);
return 0;
}
void multi(int a, int b)
{
if (a == 0)
return;
multi(a / 10, b);
if(b /10 != 0)
multi(a, b / 10);
printf("%d\n", a % 10 * b % 10);
}
list of restricions:
no loops
single function
mandatory prototype
This is a possible solution:
void multi(int a, int b)
{
// First "consume" the first parameter
if ( a > 9)
multi(a / 10, b);
// Then the second, passing only one digit of the first
if ( b > 9 )
multi(a % 10, b / 10);
// Multiply the last digits before backtracking
printf("%d\n", (a % 10) * (b % 10));
}
Testable HERE.
Here the catch is that you need to run a routine for each sub a value of a with all of sub b values.
I think you need a bit more of divide a concur approach here. you send your reduced values but you fail to treat all the cases properly.
I would suggest a simpler approach which takes the values a and b, then for each a sub value run a routine to show all of the different cases by passing the entire b each time.
so that for each sub a value you get all of the multiplications with the sub b values.
#include <stdio.h>
static void AuxMul(int a, int b)
{
int bs;
if(0 == b)
{
return;
}
bs = b%10; /*save res for multipication */
AuxMul(a, (b/10)); /*now sent it back with the same a value and reduced b value */
printf("|%d| \n", (a*bs));
}
void MultPrintRec( int a, int b)
{
int as = 0;
if (0 == a )
{
return;
}
as = a%10; /*get the value to mult. with all the b values */
MultPrintRec(a/10, b); /*do this until there is nothing to send */
AuxMul(as, b); /*send to a rec aux function that will take care of sub a value sent with all of the sub b values*/
}
int main() {
MultPrintRec(123, 567);
return 0;
}
Hope this is clear and helpful, Good luck

Is my recursion solution to this problems correct?

I need to solve this by recursion, here is what they ask to do:
Write a recursion function that takes a positive number and returning the sum(+,-) of its digits from right to left, like this way(for example): the number is 56894, the sum is 4-9+8-6+5=2.
Another example, the number is 7762348, the sum is 8-4+3-2+6-7+7=11.
Does my solution below is correct? I tried compiling it with a lot of numbers and it seems to be correct, but need to be sure.
Here is my recursive solution:
int func(int num){
if(num/10 ==0)
return num;
return (num%10) - func(num/10);
}
Your solution seems to be correct -- the problem asks you to do:
ABCD -> D - C + B - A
But your code does:
ABCD -> (D - (C - (B - A)))
Though it's not hard to show that:
(D - (C - (B - A))) == (D + -1 * (C + -1 * (B - A)) == D - C + B - A
Or some similar informal proof. But is the code considered correct if it computes num/10 twice instead of using a local variable to store the quotient:
int func(int number) {
int quotient = number / 10;
if (quotient == 0) {
return number;
}
return number % 10 - func(quotient);
}
Alternatively, this seems like an opportunity to play with div() and div_t:
#include <stdlib.h> // where div() and div_t are found
int func(int number) {
div_t result = div(number, 10);
if (result.quot == 0) {
return number;
}
return result.rem - func(result.quot);
}
Possibly avoiding yet another division on each iteration.

Binomial coefficient recursive function in C - brings wrong result, why?

beginner here trying to understand the source of the bug.
I have written this recursive function for finding the binomial coefficient between two numbers which is apparently correct in concept. However, for these two numbers, n =4 and k=2, I should be getting 6 as a result whereas I actually get 16. Any idea why is that happening?
#include<stdio.h>
int binomial(int n, int k)
{
if ((k = 0) || (k == n))
return 1;
if (k>n)
return 0;
return binomial(n - 1, k - 1) + binomial(n - 1, k);
}
int main()
{
int a, b, res;
a = 4;
b = 2;
res = binomial(a, b);
printf("The result is %d", res);
return 0;
}
This line looks wrong as it assigns 0 to k:
if ((k=0) || (k==n))
You probably mean:
if ((k==0) || (k==n))
This line
if ((k = 0) || (k == n))
should be
if ((k == 0) || (k == n))
^^
You were assigning zero to k.
As #Michael Walz points out, it's good practice to compile with -Wall to turn on all compilation warnings.

Unexpected error for recursive collatz implementation

EDIT: When I upload the code to the automatic testing platform the program doesn't crash there - it returns the correct result, but takes too long (exceeds 5 seconds)... wtf...
For university I have to implement a function that returns the number of steps taken from the input to reach 1, by following the collatz conjecture. The conjecture is very simple - given any integer number:
1. If it is even - divide it by two (n/2)
2. If it is odd - times it by 3 and add one (n*3+1)
The conjecture is that all numbers will eventually reach 1. We don't have to prove or check this, we just need to return the steps taken for a given number.
We have done this problem before, but this time we must check much larger numbers (they specify to use long instead of int) AND use recursion. They have given us skeleton code, and asked us to implement only the function - so all of my code is contained inside
int lengthCollatz(long n) { //mycode }
The skeleton code in the main collects two input values - a and b, where a < b <100000000. It checks how many steps it takes for each number between a and b, following the collatz sequence, to reach 1, and then returns the number with the highest amount of steps taken.
The function I added seems to work perfectly fine, but at larger values (when input 2 is in the millions) it seems to crash for no reason and gives no error. I've tried changing everything to unsigned longs and even long longs to see if something is overflowing - in that case the program just gets stuck... I don't understand what's wrong, please help me diagnose the error. P.S. How can I improve the speed of these calculations? We have a limit of 5 seconds.
All of my code is inside the lengthCollatz function (and the length global variable just above it) Can you identify the problem?
#include <stdio.h>
#define MAX64 9223372036854775807L /* 2ˆ63 -1 */
int length = 0;
int lengthCollatz(long n) {
length++;
//if not 1
if(n!=1){
//if odd
if(n&1) {
lengthCollatz(n=n*3+1);
}
//if even
else {
lengthCollatz(n/=2);
}
}
//if reached n = 1
else {
//return amount of steps taken
int returnLength = length;
length = 0;
return returnLength;
}
}
int main(int argc, char *argv[])
{
int n, a, b, len=-1;
scanf ("%d %d", &a, &b);
while (a <= b) {
int l = lengthCollatz(a);
if (l > len) {
n = a;
len = l;
}
a++;
}
printf("%d\n", n);
return 0;
}
Updated function:
int lengthCollatz(long n) {
if(n==1){
//return depthRecursion;
}
else {
if(n&1) {
n=n*3+1;
}
else {
n/=2;
}
return lengthCollatz(n);
}
}
Here's one alternative version which does not segfault for the input range given by OP:
int collatz(unsigned long n)
{
if (n == 1)
return 1;
else if (n & 1)
return 1 + collatz(n * 3 + 1);
else
return 1 + collatz(n >> 1);
}
AFAICT, it works OK, but it's very slow. 29 seconds on my mediocre PC. An optimized version runs two seconds faster by not calling itself when the result can be precomputed, but that version borders on manual loop unrolling. FWIW:
int collatz(unsigned long n)
{
if (n == 1)
return 1;
if (n & 1)
return 2 + collatz((n * 3 + 1) >> 1);
// Is n dividable by 16?
if (n & 0xF == 0)
return 4 + collatz(n >> 4);
// Is n dividable by 8?
if (n & 0x7 == 0)
return 3 + collatz(n >> 3);
// Is n dividable by 4?
if (n & 0x3 == 0)
return 2 + collatz(n >> 2);
return 1 + collatz(n >> 1);
}
There are of course other ways to solve this, but to finish in five seconds? Please post the solution if you find one.

Resources