Computando dígitos truncados somas de potências de pi

12

Dado um número inteiro positivo n, a soma dos primeiros n dígitos decimais da parte fracionária de π n .

Exemplo de entradas e saídas:

1 → 1
2 → 14
3 → 6
4 → 13
5 → 24
50 → 211
500 → 2305
5000 → 22852

Funções internas que calculam dígitos de π ou avaliam séries de potência ou frações contínuas não são permitidas. Aplicam-se brechas padrão . A entrada / saída pode estar em um formato conveniente (stdin, stdout, função de entrada / saída, etc.).

O código mais curto em bytes vence.

orlp
fonte
Outras funções trigonométricas que poderiam ser usadas para calcular pi, mas não necessariamente diretamente, como logaritmos arctangentes ou imaginários, também são proibidas? Além disso, existe um limite superior para n que pode falhar depois?
FryAmTheEggman 26/03
@FryAmTheEggman Se essas funções trigonométricas puderem calcular dígitos arbitrários de pi, sim, serão banidas. Seu programa deve funcionar em teoria para qualquer n , mas é perdoado se o tempo de execução ou a memória ficar muito alto.
orlp

Respostas:

4

Python - 191 bytes

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]))

~ Versão 4x mais rápida - 206 bytes

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]))

A entrada é retirada do stdin. A saída para n = 5000 leva aproximadamente 14s com o segundo script (ou 60s com o primeiro).


Uso da amostra:

$ 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

A fórmula usada é a seguinte:

onde A n é o n th alternada número , que pode ser formalmente definida como o número de permutações alternada com um conjunto de tamanho N (ver também: A000111 ). Alternativamente, a sequência pode ser definida como a composição dos Números Tangentes e Secantes ( A 2n = S n , A 2n + 1 = T n ), mais sobre isso mais tarde.

O pequeno fator de correção c n converge rapidamente para 1 quando n se torna grande e é dado por:

Para n = 1 , isso equivale a avaliar a série Leibniz . Aproximando π como 10 ½ , o número de termos necessários pode ser calculado como:

que converge (arredondado) para 17 , embora valores menores de n exijam consideravelmente mais.

Para o cálculo de A n existem vários algoritmos e até uma fórmula explícita, mas todos eles são quadráticos por n . Eu originalmente codifiquei uma implementação do Algoritmo de Seidel , mas ela se torna muito lenta para ser prática. Cada iteração requer que um termo adicional seja armazenado, e os termos aumentam em magnitude muito rapidamente (o tipo "errado" de O (n 2 ) ).

O primeiro script usa uma implementação de um algoritmo originalmente dado por Knuth e Buckholtz :

Seja T 1, k = 1 para todos k = 1..n

Os valores subsequentes de T são dados pela relação de recorrência:

T n + 1, k = 1/2 [ (k - 1) T n, k-1 + (k + 1) T n, k + 1 ]

Um n é então dado por T n, 1

(veja também: A185414 )

Embora não esteja explicitamente declarado, esse algoritmo calcula os números tangentes e secantes simultaneamente. O segundo script usa uma variação desse algoritmo de Brent e Zimmermann , que calcula T ou S , dependendo da paridade de n . A melhoria é quadrática em n / 2 , daí a melhoria da velocidade em ~ 4x.

primo
fonte
1
Excelente explicação da matemática por trás da sua resposta.
Logic Knight
3

Python 2, 246 bytes

Adotei uma abordagem semelhante à minha resposta em Calcular π com convergência quadrática . A última linha toma a enésima potência de pi e soma os dígitos. O teste N = 5000 leva cerca de um minuto.

from decimal import*
d=Decimal
N=input()
getcontext().prec=2*N
j=d(1)
h=d(2)
f=h*h
g=j/h
a=j
b=j/h.sqrt()
t=j/f
p=j
for i in bin(N)[2:]:e=a;a,b=(a+b)/h,(a*b).sqrt();c=e-a;t-=c*c*p;p+=p
k=a+b
l=k*k/f/t
print sum(map(int,`l**N`.split('.')[1][:N]))

Alguns testes:

$ echo 1 | python soln.py
1
$ echo 3 | python soln.py
6
$ echo 5 | python soln.py
24
$ echo 500 | python soln.py
2305
$ echo 5000 | python soln.py
22852

O código não destruído:

from decimal import *
d = Decimal

N = input()
getcontext().prec = 2 * N

# constants:
one = d(1)
two = d(2)
four = two*two
half = one/two

# initialise:
a = one
b = one / two.sqrt()
t = one / four
p = one

for i in bin(N)[2:] :
    temp = a;
    a, b = (a+b)/two, (a*b).sqrt();
    pterm = temp-a;
    t -= pterm*pterm * p;
    p += p

ab = a+b
pi = ab*ab / four / t
print sum(map(int, `pi ** N`.split('.')[1][:N]))
Cavaleiro Lógico
fonte
Linha 8, você pode transformar a=je p=jpara a=p=jIIRC. Talvez.
Elias Benevedes 29/05
Obrigado. Existem mais otimizações de golfe para esse código, mas ele não será competitivo sem uma reescrita usando um algoritmo sem decimal.
Logic Knight
1

Pyth, 33

s<>j^u+/*GHhyHy^TyQr*TQ0ZQT_y*QQQ

Com base nesta resposta por isaacg . Provavelmente poderia ser jogado mais. Lento.

s<>j            Digit sum of...
  ^                 
    u               Evaluate pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + ...))))
      +
        /
          *GH
          hyH
        y^TyQ       Except we generate a large integer containing 2n digits,
                    rather than a fraction.
      r*TQ0         Experimentally verified that 10*n iterations will give enough
                    precision for 2n digits (# digits correct grows faster than 2n).
      Z
    Q               To the nth power.
  T_y*QQQ         Get the last 2n^2 digits (all the fractional digits) and get the
                  first n fractional digits.
orlp
fonte
1
Essa resposta realmente precisa de pelo menos explicação suficiente para justificar que calcula dígitos suficientes para obter a resposta certa.
Peter Taylor
@ PeterTaylor Vou adicionar uma explicação amanhã, prestes a ir para a cama.
orlp
Cada iteração produz um bit correto (consulte o Apêndice A ). Os dígitos 2n devem exigir ~ 6,64n iterações.
Primo 29/05