Implementing the Tak function using tail recursion - c++

Is it possible to implement the Tak function:
tail recursively in C/C++ in a way so that gcc/g++ can perform tail-recursion optimization?
I'm not sure if the nested recursive function calls will confuse the compiler.

Tail recursion optimization in C++ requires that there only be 1 recursive call (which basically allows it to be converted to a loop) and that recursive call is the last operation in the function:
Example:
unsigned int f( unsigned int a )
{
if ( a == 0 )
{
return a;
}
return f( a - 1 ); // tail recursion
}
Since the Tak function requires 4 recursive calls per "iteration":
int tak(int x, int y, int z)
{
if (x >= y)
{
return z;
}
else
{
return tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y)); // this is why it cannot happen
}
}
As you can see, the last call is recursive, but it has 3 recursive calls inside it. This prevents tail-recursion optimization (and there is no logical method for converting this into a non-recursive-loop - which is required to obtain tail-recursion optimization).
Another way it can be implemented is:
int tak(int x, int y, int z)
{
while (x > y)
{
int oldx = x, oldy = y;
x = tak(x - 1, y, z);
y = tak(y - 1, z, oldx);
if (x <= y)
break;
z = tak(z - 1, oldx, oldy);
}
return z;
}
Which again shows that even in a loop form, it is still recursive, preventing tail-recursion optimization.

Going straight from your math definition, we can just write the function as:
int tak(int x, int y, int z){
if(x>y)
return tak(tak(1-x,y,z), tak(y-1,z,x), tak(z-1,x,y));
else
return z;
}
However you can't do it with tail-recrusion as it cannot be converted into a loop. Since there is more than one recrusion call.

Related

In a recursive function, how can I jump to a different function call on the stack?

To make my question more clear, I'll give an example. Say I want to implement a recursive function that sums up the range of numbers from [1-10] and [15-20], skipping (10-15). I would want to add up [15-20] and skip the function calls on stack of (10-15), and continue with [1-10]. How can I do this?
int summation(int x, int y) {
if(x == y) return x;
// Catch here and return sum of 15-20 back to calls of 1-10
if(x == 10)
catch(int n)
return n;
int sum = x + summation(x+1,y);
// Skip function calls 10-15
if(x==15) throw sum;
return sum;
}
summation(1,20) // >> 160 or [1-10] = 55, [15,20] = 105
I know how to solve the above example with a different approach, but this example gives an idea of what I'm trying to do.
In order to set the try/catch in the right stack frame, you need to know the edge of the skip interval before you recurse deeper. Given that, it will be better to just never make the useless function calls instead of using an exception to unwind them. For example:
int summation(int const x, int const y)
{
if(x == y) return x;
int const next = (x==10)? 15: (x+1); // skip from 10 to 15 directly
return x + summation(next, y);
}
Avoiding exceptions also gives you the possibility to write the function tail-recursively:
int summation(int const x, int const y, int partial_sum = 0)
{
partial_sum += x;
if(x == y) return partial_sum;
int const next = (x==10)? 15: (x+1); // skip from 10 to 15 directly
return summation(next, y, partial_sum);
}
Keep the function simple.
int summation(int x, int y) {
if(x == y) return x;
return x + summation(x+1,y);
}
and use
summation(1, 10) + summation(15, 20);
on the client side.
You can make the client side a little bit simpler by adding another function that takes care of the numbers to skip.
int summation_with_skip(int x1, int x2, int x3, int x4) {
return summation(x1, x2) + summation(x3, x4);
}
and use
summation_with_skip(1, 10, 15, 20);
If you must have the logic to skip items in the function, you can use
int summation_with_skip(int x1, int x2, int x3, int x4)
{
if ( x1 > x4 )
{
return 0;
}
int s = summation(x1+1, x2, x3, x4)
if ( (x1 > x2) && (x1 < x3) )
{
return s;
}
else
{
return x1 + s;
}
}
I like the idea of passing all arguments to the function.
well, this would be a solution without throw&catch
still an odd solution for the given problem
int summation(int x, int y)
{
if(x > y) return 0;
if ((x >= 10) && (x <= 15))
{
return summation(x+1, y);
}
else
{
return x + summation(x+1, y);
}
}

Using the same parameter in different functions

So I was curious about something. I have two functions, both work the way I want them to, and they are as follows:
//this function returns the absolute value of a number
int abs(int y) {
if (y < 0) {
return -1 * y;
}
return y;
}
//gives a random number, multiplied by x, in the range 1-y
int randomNum(int x, int y) {
srand((int)time(0));
return abs(x * rand() % y) + 1;
}
They both work, so their functionality is not the problem. But if you'll notice, they both use a parameter called "int y."
My question is, despite the fact that these two functions work, is this bad practice that might screw me over in more complex programs? Or does it not matter because the variables are local to their respective functions?
I mean, it's obviously no big deal if I change one of the "int y" parameters to something else, I'm just curious, is all.
I think it is okay for simple programs.
However, you should name a variable using the same care with which you
name a first-born child.
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
For instance, nobody prefers to read the declaration int foo(int x, int y, int z, int xx, int bb, int cc .....)
Whenever there is a variable inside braces { }, it is local to the scope. Once out of the braces it simply dies.
Now the code that you are asking,
// y is declared in abs and is alive only in the abs
int abs(int y) {
if (y < 0) {
return -1 * y;
}
return y;
}
// the previous y dies here and is inaccessible.
// a new instance of y is created in randomNum and it's valid till the brace ends
int randomNum(int x, int y) {
srand((int)time(0));
return abs(x * rand() % y) + 1;
}
Now a little thing to try out as pointed out by Jawad Le Wywadi
int main()
{
int a = 0;
++a;
{
int a = 1;
a = 42;
cout << a;
}
cout << a;
}
Try it yourself and let us know what do you realize in the comments.

Macros in C++ breaks with postfix increments

I need a working MAX macros (without(!) declaring main function) which assign 'r' the maximum of numbers 'a' and 'b'. This code breaks in compilation. How can it be fixed?
#define MAX(x, y, r) ((x) > (y) ? (r = x) : (r = y))
int x = 10;
int y = 20;
int r;
MAX(x, y, r);
Thanks for watching!
UPD: Some revision to clear the full task:
#import <iostream>
#define MAX(x, y, r) ((x) > (y) ? (r = x) : (r = y))
int x = 1;
int y = 1;
int r = 1;
int main()
{
MAX(x++, y, r);
std::cout << r;
return 0;
}
The result of this code is 1, and need to be 2. So I need another logic in my macros to consider all postfix increments
You can't use this macro outside of a function, because it's an arbitrary expression, that's why you're getting an error.
Just move the invocation of the macro into function scope and it will work:
#define MAX(x, y, r) ((x) > (y) ? (r = x) : (r = y))
int x = 10;
int y = 20;
int r;
int main()
{
MAX(x, y, r);
}
Using macros in this case is, however, unnecessary (unless this is just an exercise to learn macro usage); making max a function (or, better yet, using std::max) would be a better and less error-prone way.
It doesn't work because you can't put arbitrary expressions at file-scope. I have a couple of suggestions:
Don't use global variables unless you really, really have to. They'll just cause you pain.
Don't use macros unless you really, really have to. They'll just cause you pain.
Here's what I'd do:
int main()
{
int x = 10;
int y = 20;
int r = std::max(x, y);
//pass x, y and r as arguments to functions rather than using globals
}

Returning the actual value of maximum of absolutes of variables

I want to find the maximum of the absolute of two variables, and return the actual value of that variable, rather than the absolute value of that variable.
For example:
int x = 3;
int y = -5;
int z = max(abs(x), abs(y))
Will just set z to 5, whereas I want it to return -5. Is there a C++ function to perform this?
If you're using C++11, with the STL you could use a vector of int, max_element and a lambda Compare
std::vector<int> values = {3, -5};
int largest_abs = *std::max_element(values.begin(), values.end(), [](const int& a, const int& b)
{
return abs(a) < abs(b);
});
This returns the iterator between the start and end of values, whose absolute value is the largest. (this is found through the comparator) The * is then used to convert the iterator (returned by std::max_element) to an int
It's not a commonly used function, but writing your own function is trivial.
int max_abs(int x, int y)
{
if (x == INT_MIN || y == INT_MIN)
return INT_MIN;
return (abs(x) > abs(y)) ? x : y;
}
int z = (max(abs(x), abs(y)) == abs(x)) ? x : y;
This is like an if-condition. Its equivalent to
int z = x;
if(max(abs(x), abs(y)) != abs(z))
z = y;
But much shorter.
There is no function in the STL to fit into your needs directly, so you need to make your own and this one could be one version.
A more handy one can be int z = (abs(y) < abs(x)) ? x : y thought.

Returning multiple values and default parameters in C++

I'm trying to make a function that takes in either 1 or 3 parameters, and returns either 1 or 3 values (based on parameters passed).
If 1 parameter is passed then the function uses default values for the other 2 arguments.
If 3 parameters are passed then it uses those values.
bool foo( bool x, int &y = 0, int &z = 0) {
x = true; y = y + 1; z = z + 2;
return x;
}
Is this possible in C++ or am I confused with Java functions.
You can do it with two functions:
bool foo( bool x, int &y, int &z) {
x = true; // this isn't really what it does, is it?
y = y + 1; z = z + 2;
return x;
}
bool foo(bool x)
{
int a = 0, b = 0;
return foo(x,a,b);
}
Any function always returns only 1 value. Returning 2 or more values is not possible directly.
Indirectly, it happens when you pass parameters by reference. Since the two parameters &y and &z are passed by references, hence changes to them can be reflected back directly.
You can do this by passing by reference..
by doing so you are making a method that points to a memory location.
When that memory location is changed, then your value is changed.
Link
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr233.htm
You cannot do that this way. You can, however, overload that function with different number of parameters, and return, maybe, a std::vector or std::list with the results.
EDIT:
Being more sophisticated, you can use tuples for that:
typedef boost::tuple<bool,int,int> my_data_t;
my_data_t my_tuple(true, 1, 0);
then, you define your function like this:
bool foo( my_data_t & t)
{
t.get<0>() = true;
int& y = t.get<1>();
y = y+1;
int& z = t.get<2>();
z = z+2;
return t.get<0>();
}
and call it this way:
bool result = foo ( my_tuple );
then, out of the function, you'll see my_tuple.get<1>() (the corresponding to y) as 2 (1+1).
I am not sure what you are trying to do, but you can kind of return multiple values of different type using boost::tuple.
boost::tuple<bool, int, int> foo( bool x, int y = 0, int z = 0) {
x = true; y = y + 1; z = z + 2;
return boost::make_tuple(x, y, z);
}
int main() {
boost::tuple<bool, int, int> result = foo(x, 1, 2);
std::cout << boost::get<0>(result) << boost::get<1>(result) << boost::get<2>(result);
}
You could also use boost::optional, if you only want to return x, if only 1 parameter is passed.
Btw. tuple is available in C++11 too.