ограничения рекурсии в python
почему рекурсия выполняется только 995 раз? и как это можно исправить?
Ответы (2 шт):
Поскольку в комментарии речь зашла про конкретный случай, предлагаю как вариант метод быстрый, но, увы, не сильно точный. Зато считается примерно секунду на предложенном автором вопроса числе:
from numba import njit
@njit()
def factorial(n):
s = 1
d = 0
for i in range(2, n + 1):
s *= i
while s >= 10:
s /= 10
d += 1
return s,d
s,d = factorial(37_826_497)
print(f'{s}e+{d}')
Вывод:
4.349383396225913e+270213647
Можно увеличить глубину рекурсии до примерно 22000 (так было когда-то, на Python 3.10 предел 14542 на моей машине). Можно сменить интерпретатор Питона на безстековый - глубина рекурсии будет ограничена только доступной памятью: около 40 миллионов вызовов на 32GB. Последнего числа вам будет достаточно если вы напишете программу достаточно правильно. (Разбор рекурсии)
По времени работы рекурсивная и итеративная программы будут одинаковы: и там и там всё время уйдёт на последовательные умножения. Накладные расходы на цикл или на рекурсию вы даже не заметите.
В соседнем ответе факториал считается приблизительно последовательным умножением и отбрасыванием младших цифр. Ещё один способ - заменить умножение числе на сложение их натуральных логарифмов. Натуральный логарифм перевести в десятичный и напечатать его:
import numpy as np
def big_factorial(n):
i = np.arange(2, n + 1)
lg = np.sum(np.log(i)) / np.log(10)
m, e = np.modf(lg)
return 10 ** m, int(e)
m, e = big_factorial(int(input()))
print(f'{m}e+{e}')
$ time echo 37826497 | python big-factorial.py 4.349383221475161e+270213647 real 0m1.153s user 0m1.212s sys 0m0.552s
Семь знаков этого ответа совпадают с соседним ответом, который, как сейчас станет ясно, более точный.
Можно ли получить точные цифры? Да, можно. Этот код за полтора часа вычисляет факториал и выводит его старшие цифры точно:
import math
n, d = map(int, input().split())
f = math.factorial(n);
e = int(f.bit_length() / math.log(10, 2)) - d
b = 10 ** e
print(f'{f // b}...')
$ time echo 37826497 20 | python big-factorial-exact.py 434938339623008896624... real 89m13.142s user 89m7.112s sys 0m2.428s
Можно точно оценить интервал в котором лежит факториал. Потребуется меньше минуты:
def factorial(n, d):
e = 0
m = 10 ** d
low = 1
high = 1
for i in range(2, n + 1):
low *= i
c = 0
while low >= m:
low //= 10
c += 1
f = 10 ** c
e += c
high = (high * i + f - 1) // f
return low, high, e
n, d = map(int, input().split())
low, high, e = factorial(n, d)
print(low, f'* 10^{e}')
print(high, f'* 10^{e}')
$ time echo 37826497 20 | python big-factorial-interval.py 43493833962268738973 * 10^270213628 43493833962333044522 * 10^270213628 real 0m47.203s user 0m47.196s sys 0m0.000s