Реализация функции Tak с использованием хвостовой рекурсии

0

Возможно ли реализовать функцию Tak:

Изображение 174551

хвост рекурсивно в C/C++ таким образом, чтобы gcc/g++ мог выполнять оптимизацию хвостовой рекурсии?
Я не уверен, что вызовы вложенной рекурсивной функции путают компилятор.

  • 0
    Я не вижу, как это было бы? Так как это только начало бы делать их все, и продолжать ветвление?
Теги:
compiler-optimization
tail-recursion

2 ответа

1

Оптимизация рекурсии хвоста в C++ требует, чтобы был только 1 рекурсивный вызов (который в основном позволяет преобразовать его в цикл), а рекурсивный вызов является последней операцией в функции:

Пример:

unsigned int f( unsigned int a ) 
{
   if ( a == 0 ) 
   {
      return a;
   }
   return f( a - 1 );   // tail recursion
}

Поскольку для функции "Tak" требуется 4 рекурсивных вызова на "итерацию":

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

Как вы можете видеть, последний вызов является рекурсивным, но в нем есть 3 рекурсивных вызова. Это предотвращает оптимизацию хвостовой рекурсии (и нет логического метода для преобразования этого в нерекурсивный цикл, который необходим для оптимизации хвостовой рекурсии).

Другой способ, которым он может быть реализован:

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

Что еще раз показывает, что даже в форме цикла он все еще рекурсивно, предотвращая оптимизацию хвостовой рекурсии.

  • 0
    Может ли компилятор преобразовать прямую реализацию в реализацию цикла?
  • 0
    @ jh314 Что вы подразумеваете под «прямой реализацией»?
Показать ещё 2 комментария
0

Исходя из вашего определения математики, мы можем просто написать функцию как:

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

Однако вы не можете сделать это с помощью хвостика, поскольку он не может быть преобразован в цикл. Поскольку существует более одного призыва к рекрутингу.

  • 0
    Количество рекурсивных вызовов не является важной переменной. Есть функции с одним рекурсивным вызовом, которые нельзя превратить в цикл, и есть функции с большим количеством рекурсивных вызовов, которые могут это сделать. Что важно, так это местоположение звонка.
  • 0
    Спасибо, Джулс. Ценить это!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню