Функция может фактически вызвать переполнение стека (каждый уровень рекурсии будет занимать часть стека до тех пор, пока она не будет полностью израсходована).
Как уже упоминалось, вы можете преобразовать рекурсивную функцию в цикл, который в этом случае будет простым, или вы можете изменить рекурсию, чтобы позволить оптимизацию хвостового вызова (чтобы компилятор преобразовал рекурсию в цикл) .
Ради этого, чтобы превратить его в хвостовой рекурсивный вызов, последний оператор функции должен быть возвращением с результатом, полученным из рекурсивного вызова. Ваш код не может быть оптимизирован, потому что ваш оператор возврата содержит m*factorial(n-1)
, то есть вы не возвращаете значение рекурсии, но фактически работаете с ним перед возвратом.
Преобразование, чтобы сделать его хвостовым рекурсивным, требует нажатия умножения на рекурсивный вызов, и это обычно выполняется как дополнительный аргумент, который сохраняет временный результат:
unsigned long factorial_tail_recursive(
unsigned long n, // number to calculate factorial
unsigned long temp_result // accumulated result
)
{
return n == 0? tmp_result
: factorial_tail_recursive( n-1, n*temp_result );
}
// syntactic sugar to offer the same interface
unsigned long factorial( unsigned long n ) {
return factorial_tail_recursive( n, 1 ); // accumulated result initialized to 1
}
Но опять же, для этой конкретной проблемы эффективное итеративное решение, вероятно, легче получить правильное. Просто сохраните накопленный результат во временной переменной и выполните цикл, пока аргумент не уменьшится до 1.