Я знаю, что двухфакторная хвостовая рекурсивная функция должна вызывать рекурсивную функцию в конце и ничего больше
Это правда, поэтому
return (n*Factorial(n - 1));
или
return (factorial / DoubleFactorialTail(n - 1, fact));
Не собирается работать.
Шаблон должен быть буквально
return CallToRecursive(args);
Причина в том, что рекурсивная оптимизация хвоста позволяет CallToRecursive(args);
возврат к вызывающей стороне этой функции и не добавляет фрейм в стек вызовов.
Если вы добавляете код, который должен дополнительно обрабатывать возвращаемое значение, тогда ему нужен кадр в стеке вызовов для хранения возвращаемого значения и точки возврата, и это не TCO.
Чтобы подойти к этому, обычно передают незавершенную работу следующему вызову.
long long int FactorialTCO(int n, long long factSoFar)
{
if (n < 0)
return 0;
if (n == 0 || n == 1)
return factSoFar;
return FactorialTCO(n - 1, n * factSoFar);
}
long long int Factorial(int n) {
return FactorialTCO(n, 1);
}
Обратите внимание, что эта строка:
return FactorialTCO(n - 1, n * factSoFar);
Возвращает именно то, что возвращается от рекурсивного вызова. , Это означает, что компилятору не нужно создавать новый кадр стека, и этот вызов вернется к вызывающей функции этой функции. Делая это несколько раз, мы можем эффективно перейти обратно к первому вызывающему, когда закончим, вместо того, чтобы разматывать фрейм стека.
Я оставляю преобразование double до вас или других.