Пітон - 191 байт
t=i=1L;k=n=input();f=2000*20**n;A=range(n+1)
for k in range(2,n):A=[(A[j-1]+A[j+1])*j>>1for j in range(n-k+1)];f*=k
while k:k=(1-~i*n%4)*f/A[1]/i**n;t+=k;i+=2
print sum(map(int,`t`[-n-4:-4]))
~ В 4 рази швидша версія - 206 байт
t=i=1L;k=n=input();f=2000*20**n;A=[0,1]+[0]*n
for k in range(1,n):
f*=k
for j in range(-~n/2-k+1):A[j]=j*A[j-1]+A[j+1]*(j+2-n%2)
while k:k=(1-~i*n%4)*f/A[1]/i**n;t+=k;i+=2
print sum(map(int,`t`[-n-4:-4]))
Введення взято з stdin. Вихід для n = 5000 займає приблизно 14 секунд з другим сценарієм (або 60-х з першим).
Використання зразка:
$ echo 1 | python pi-trunc.py
1
$ echo 2 | python pi-trunc.py
14
$ echo 3 | python pi-trunc.py
6
$ echo 4 | python pi-trunc.py
13
$ echo 5 | python pi-trunc.py
24
$ echo 50 | python pi-trunc.py
211
$ echo 500 | python pi-trunc.py
2305
$ echo 5000 | python pi-trunc.py
22852
Використовувана формула така:
![](https://chart.googleapis.com/chart?cht=tx&chl=%5Cpi%5En%3D2%5E%7Bn%2B1%7D%5Cfrac%7B%28n-1%29%21%7D%7BA_%7Bn-1%7D%7Dc_n)
де A n - n- й змінний номер , який формально можна визначити як кількість чергуються перестановок на множині розміру n (див. також: A000111 ). Альтернативно, послідовність можна визначити як склад дотичних чисел і таємних чисел ( A 2n = S n , A 2n + 1 = T n ), про це пізніше.
Малий поправочний коефіцієнт c n швидко переходить до 1, оскільки n стає великим, і задається:
![](https://chart.googleapis.com/chart?cht=tx&chl=c_n%3D%5Csum%5Climits_%7B_%7Bk%3D0%7D%7D%5E%7B_%5Cinfty%7D%7B%5Cleft%28%5Cfrac%7B%28-1%29%5Ek%7D%7B2k%2B1%7D%5Cright%29%5En%7D)
Для n = 1 це означає оцінку серії Лейбніца . Облікуючи π як 10 ½ , кількість необхідних термінів можна обчислити як:
![](https://chart.googleapis.com/chart?cht=tx&chl=%5Cfrac%7B1%7D%7B2%7D%5Cleft%5B1%2B%5Cleft%2810%5E%7B%5Cfrac%7B3n%7D%7B2%7D%2B3%7D%5Cright%29%5E%7B%5Cfrac%7B1%7D%7Bn%7D%7D%5Cright%5D)
який збігається (округляється) до 17 , хоча менші значення n вимагають значно більше.
Для обчислення A n існує кілька алгоритмів і навіть явна формула, але всі вони є квадратичними по n . Я спочатку кодував реалізацію алгоритму Зейделя , але це виявляється занадто повільним, щоб бути практичним. Кожна ітерація потребує збереження додаткового терміна, а умови збільшуються на величину дуже швидко («неправильний» вид O (n 2 ) ).
Перший сценарій використовує реалізацію алгоритму, який спочатку давали Кнут та Бакхолц :
Нехай T 1, k = 1 для всіх k = 1..n
Наступні значення Т задаються відношенням рецидивування:
T n + 1, k = 1/2 [ (k - 1) T n, k-1 + (k + 1) T n, k + 1 ]
Тоді A n задається T n, 1
(див. також: A185414 )
Хоча це прямо не вказано, цей алгоритм обчислює і дотичні числа, і таємні числа одночасно. Другий сценарій використовує варіацію цього алгоритму Брент та Циммерманна , яка обчислює або T, або S , залежно від паритету n . Поліпшення є квадратичним на n / 2 , отже, ~ 4-кратне підвищення швидкості.