Run of Digits in Pi


13

Il tuo obiettivo è generare la sequenza strettamente crescente di cifre consecutive e identiche di pi (π). Ogni termine nella sequenza deve essere una cifra più lunga della precedente. Quindi 3(0a cifra di pi) è la prima volta che si verifica una serie di cifre (lunghezza 1). Il prossimo che si verifica è 33(cifre 24 e 25 di pi). Naturalmente, questa sequenza richiede che le cifre di pi siano nella base 10 .

Quelli finora noti , e i primi sei compaiono tutti entro le prime 800 cifre:

3
33
111
9999
99999
999999
3333333
44444444
777777777
6666666666
... (not in first 2 billion digits)

Nota che i nove consecutivi si verificano tutti insieme, nella stessa corsa, quindi se la prossima corsa più grande che hai trovato fosse 1000 0s consecutivi , questo riempirebbe più termini della sequenza.

Non ho trovato più termini con il mio programma. So che non ci sono più termini entro le prime 50000 cifre o più. Il mio programma stava impiegando troppo tempo con 500000 cifre, quindi ho rinunciato.

Implementazione di riferimento

Potresti:

  • Stampa la sequenza per sempre
  • Prendi un numero intero ne trova i primi nnumeri nella sequenza
  • Prendi un numero intero ne trova i numeri nella sequenza contenuta nelle prime ncifre di pi.

Assicurati di specificare quale fa il tuo codice. Il numero npuò essere zero o uno indicizzato.

Ispirato da questa domanda mathoverflow .


1
Correlato - che corse di 9 secondi hanno causato mal di testa a molte risposte: P
Mego,

Ti è permesso avviare l'output con la sequenza vuota?
LegionMammal978,

2
Inoltre, il termine successivo della sequenza sembra essere 3333333 nelle cifre da 10 ^ -710100 a 10 ^ -710106. Il valore per n = 8 non appare nelle prime 5.000.000 di cifre.
LegionMammal978,

4
Altri due termini: 44444444 alle cifre da 10 ^ -22931745 a 10 ^ -22931752 e 777777777 alle cifre da 10 ^ -24658601 a 10 ^ -24658609. Il valore per n = 10 non appare nelle prime 100.000.000 di cifre.
LegionMammal978,

1
Un altro termine: 6666666666 a 10 ^ -386980412. L'undicesimo termine non appare nelle prime 2 000 000 000 cifre.
primo

Risposte:


5

Mathematica, 85 byte

FromDigits/@DeleteDuplicatesBy[Join@@Subsets/@Split@RealDigits[Pi,10,#][[1]],Length]&

Funzione anonima. Prende n come input e restituisce gli elementi della sequenza nelle prime n cifre di π. L'output è in forma di {0, 3, 33, 111, ...}.


4

Python 2, 110 byte

n=input()
x=p=7*n|1
while~-p:x=p/2*x/p+2*10**n;p-=2
l=m=0
for c in`x`:
 l=l*(p==c)+1;p=c
 if l>m:m=l;print p*l

Il numero massimo di cifre da controllare è preso dallo stdin. 10.000 cifre termina in circa 2 secondi con PyPy 5.3.

Esempio di utilizzo

$ echo 10000 | pypy pi-runs.py
3
33
111
9999
99999
999999

Qualcosa di utile

from sys import argv
from gmpy2 import mpz

def pibs(a, b):
  if a == b:
    if a == 0:
      return (1, 1, 1123)
    p = a*(a*(32*a-48)+22)-3
    q = a*a*a*24893568
    t = 21460*a+1123
    return (p, -q, p*t)
  m = (a+b) >> 1
  p1, q1, t1 = pibs(a, m)
  p2, q2, t2 = pibs(m+1, b)
  return (p1*p2, q1*q2, q2*t1 + p1*t2)

if __name__ == '__main__':
  from sys import argv
  digits = int(argv[1])

  pi_terms = mpz(digits*0.16975227728583067)
  p, q, t = pibs(0, pi_terms)

  z = mpz(10)**digits
  pi = 3528*q*z/t

  l=m=0
  x=0
  for c in str(pi):
   l=l*(p==c)+1;p=c
   if l>m:m=l;print x,p*l
   x+=1

Per questo sono passato da Chudnovsky a Ramanujan 39. Chudnovsky ha esaurito la memoria sul mio sistema poco dopo 100 milioni di cifre, ma Ramanujan è arrivato a 400 milioni, in soli 38 minuti circa. Penso che questo sia un altro caso in cui il tasso di crescita più lenta dei termini vince alla fine, almeno su un sistema con risorse limitate.

Esempio di utilizzo

$ python pi-ramanujan39-runs.py 400000000
0 3
25 33
155 111
765 9999
766 99999
767 999999
710106 3333333
22931752 44444444
24658609 777777777
386980421 6666666666

Generatori più veloci e illimitati

L'implementazione di riferimento fornita nella descrizione del problema è interessante. Utilizza un generatore illimitato, prelevato direttamente dalla carta Unbounded Spigot Algorithms for the Digits of Pi . Secondo l'autore, le implementazioni fornite sono "volutamente oscure", quindi ho deciso di fare nuove implementazioni di tutti e tre gli algoritmi elencati dall'autore, senza offuscamento deliberato. Ho anche aggiunto un quarto, basato su Ramanujan # 39 .

try:
  from gmpy2 import mpz
except:
  mpz = long

def g1_ref():
  # Leibniz/Euler, reference
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 3
  while True:
    n = (q+r)/t
    if n*t > 4*q+r-t:
      yield n
      q, r = 10*q, 10*(r-n*t)
    q, r, t = q*i, (2*q+r)*j, t*j
    i += 1; j += 2

def g1_md():
  # Leibniz/Euler, multi-digit
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 3
  z = mpz(10)**10
  while True:
    n = (q+r)/t
    if n*t > 4*q+r-t:
      for d in digits(n, i>34 and 10 or 1): yield d
      q, r = z*q, z*(r-n*t)
    u, v, x = 1, 0, 1
    for k in range(33):
      u, v, x = u*i, (2*u+v)*j, x*j
      i += 1; j += 2
    q, r, t = q*u, q*v+r*x, t*x

def g2_md():
  # Lambert, multi-digit
  q, r, s, t = mpz(0), mpz(4), mpz(1), mpz(0)
  i, j, k = 1, 1, 1
  z = mpz(10)**49
  while True:
    n = (q+r)/(s+t)
    if n == q/s:
      for d in digits(n, i>65 and 49 or 1): yield d
      q, r = z*(q-n*s), z*(r-n*t)
    u, v, w, x = 1, 0, 0, 1
    for l in range(64):
      u, v, w, x = u*j+v, u*k, w*j+x, w*k
      i += 1; j += 2; k += j
    q, r, s, t = q*u+r*w, q*v+r*x, s*u+t*w, s*v+t*x

def g3_ref():
  # Gosper, reference
  q, r, t = mpz(1), mpz(180), mpz(60)
  i = 2
  while True:
    u, y = i*(i*27+27)+6, (q+r)/t
    yield y
    q, r, t, i = 10*q*i*(2*i-1), 10*u*(q*(5*i-2)+r-y*t), t*u, i+1

def g3_md():
  # Gosper, multi-digit
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 60
  z = mpz(10)**50
  while True:
    n = (q+r)/t
    if n*t > 6*i*q+r-t:
      for d in digits(n, i>38 and 50 or 1): yield d
      q, r = z*q, z*(r-n*t)
    u, v, x = 1, 0, 1
    for k in range(37):
      u, v, x = u*i*(2*i-1), j*(u*(5*i-2)+v), x*j
      i += 1; j += 54*i
    q, r, t = q*u, q*v+r*x, t*x

def g4_md():
  # Ramanujan 39, multi-digit
  q, r, s ,t = mpz(0), mpz(3528), mpz(1), mpz(0)
  i = 1
  z = mpz(10)**3511
  while True:
    n = (q+r)/(s+t)
    if n == (22583*i*q+r)/(22583*i*s+t):
      for d in digits(n, i>597 and 3511 or 1): yield d
      q, r = z*(q-n*s), z*(r-n*t)
    u, v, x = mpz(1), mpz(0), mpz(1)
    for k in range(596):
      c, d, f = i*(i*(i*32-48)+22)-3, 21460*i-20337, -i*i*i*24893568
      u, v, x = u*c, (u*d+v)*f, x*f
      i += 1
    q, r, s, t = q*u, q*v+r*x, s*u, s*v+t*x

def digits(x, n):
  o = []
  for k in range(n):
    x, r = divmod(x, 10)
    o.append(r)
  return reversed(o)

Appunti

Sopra sono 6 implementazioni: le due implementazioni di riferimento fornite dall'autore (denotate _ref) e quattro che calcolano i termini in batch, generando più cifre contemporaneamente ( _md). Tutte le implementazioni sono state confermate a 100.000 cifre. Quando ho scelto le dimensioni dei lotti, ho scelto valori che lentamente perdono precisione nel tempo. Ad esempio, g1_mdgenera 10 cifre per batch, con 33 iterazioni. Tuttavia, questo produrrà solo ~ 9,93 cifre corrette. Quando la precisione si esaurisce, la condizione di controllo fallisce, innescando l'esecuzione di un batch aggiuntivo. Questo sembra essere più performante di una precisione extra lentamente non necessaria nel tempo.

  • g1 (Leibniz / Euler)
    Viene jmantenuta una variabile aggiuntiva , che rappresenta 2*i+1. L'autore fa lo stesso nell'implementazione di riferimento. Il calcolo nseparato è molto più semplice (e meno oscuro), perché utilizza i valori correnti di q, re t, piuttosto che il successivo.
  • g2 (Lambert)
    Il controllo n == q/sè certamente piuttosto lassista. Quello dovrebbe leggere n == (q*(k+2*j+4)+r)/(s*(k+2*j+4)+t), dove jè 2*i-1ed kè i*i. A iterazioni più elevate, i termini re tdiventano sempre meno significativi. Come è, è buono per le prime 100.000 cifre, quindi probabilmente è buono per tutti. L'autore non fornisce alcuna implementazione di riferimento.
  • g3 (Gosper)
    L'autore ipotizza che non sia necessario verificare che nnon cambierà nelle successive iterazioni e che serva solo a rallentare l'algoritmo. Anche se probabilmente è vero, il generatore sta trattenendo circa il 13% in più di cifre corrette rispetto a quelle attualmente generate, il che sembra piuttosto dispendioso. Ho aggiunto il check-in e aspetto che 50 cifre siano corrette, generandole tutte in una volta, con un notevole guadagno in termini di prestazioni.
  • g4 (Ramanujan 39)
    Calcolato come

    Sfortunatamente, snon azzera, a causa della composizione iniziale (3528 ÷), ma è ancora significativamente più veloce di g3. La convergenza è di ~ 5,89 cifre per termine, 3511 cifre vengono generate alla volta. Se è un po 'troppo, anche generare 271 cifre per 46 iterazioni è una scelta decente.

Tempi

Preso sul mio sistema, solo a scopo di confronto. I tempi sono elencati in secondi. Se un tempo ha richiesto più di 10 minuti, non ho eseguito ulteriori test.

            |  g1_ref |  g1_md  |  g2_md  |  g3_ref |  g3_md  |  g4_md 
------------+---------+---------+---------+---------+---------+--------
    10,000  |  1.645  |  0.229  |  0.093  |  0.312  |  0.062  |  0.062 
    20,000  |  6.859  |  0.937  |  0.234  |  1.140  |  0.250  |  0.109 
    50,000  |  55.62  |  5.546  |  1.437  |  9.703  |  1.468  |  0.234 
   100,000  |  247.9  |  24.42  |  5.812  |  39.32  |  5.765  |  0.593 
   200,000  |  2,158  |  158.7  |  25.73  |  174.5  |  33.62  |  2.156 
   500,000  |    -    |  1,270  |  215.5  |  3,173  |  874.8  |  13.51 
 1,000,000  |    -    |    -    |  1,019  |    -    |    -    |  58.02 

È interessante che g2alla fine superi g3, nonostante un tasso di convergenza più lento. Sospetto che ciò sia dovuto al fatto che gli operandi crescono a un ritmo significativamente più lento, vincendo nel lungo periodo. L' g4_mdimpianto più veloce è circa 235 volte più veloce dell'impianto g3_refsu 500.000 cifre. Detto questo, c'è ancora un notevole sovraccarico per lo streaming delle cifre in questo modo. Il calcolo diretto di tutte le cifre utilizzando Ramanujan 39 ( fonte Python ) è circa 10 volte più veloce.

Perché non Chudnovsky?

L'algoritmo di Chudnovsky richiede una radice quadrata di piena precisione, che onestamente non sono sicuro su come lavorare - supponendo che potrebbe essere affatto. Ramanujan 39 è alquanto speciale in questo senso. Tuttavia, il metodo sembra favorire le formule simili a quelle di Machin, come quelle usate da y-cruncher, quindi potrebbe essere una strada che vale la pena esplorare.


TIL Ideone supporta Pypy. Quindi il 2o programma è stato creato per la velocità?
mbomb007,

@ mbomb007 "Quindi il 2 ° programma è stato creato per la velocità?" È. Penso che la sfida sarebbe stata altrettanto interessante come un codice più veloce .
primo

Stesso. Ho considerato entrambi. Idk come si sentono le persone a ripubblicare con un tag diverso. Potrebbe essere più utile se deve essere aggiunto all'OEIS (che non contiene questa sequenza)
mbomb007

3

Haskell, 231 byte

import Data.List
g(q,r,t,k,n,l)|4*q+r-t<n*t=n:g(10*q,10*(r-n*t),t,k,div(10*(3*q+r))t-10*n,l)|0<1=g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
p=nubBy(\x y->length x==length y).concatMap inits.group$g(1,0,1,1,3,3) 

Questo utilizza il algoritmi Spigot illimitati per le cifre di Pi di Jeremy Gibbons, 2004. Il risultato è p. Tecnicamente, dovrebbe supportare infinite sequenze di output, ma ciò potrebbe richiedere del tempo (ed è limitato dalla memoria).


3

Python 2, 298 byte

Si noti che il codice per la generazione di pi è preso dall'implementazione del PO.

def p():
 q,r,t,j=1,180,60,2
 while 1:
  u,y=3*(3*j+1)*(3*j+2),(q*(27*j-12)+5*r)//(5*t)
  yield y
  q,r,t,j=10*q*j*(2*j-1),10*u*(q*(5*j-2)+r-y*t),t*u,j+1
p=p()
c=r=0
d=[0]
while 1:
 t=p.next()
 if t==d[len(d)-1]:d.append(t)
 else:d=[t]
 if len(d)>r:r=len(d);print"".join([`int(x)`for x in d])
 c+=1

Il mio primo tentativo di giocare a golf a Python. Emette la sequenza per sempre.


Potresti spiegare come calcoli πqui? Tu, ovviamente, calcoli pi, giusto?
R. Kap

Non puoi provare adesso, ma non stai calcolando πper sempre lì?
Yytsi,

@TuukkaX non appare così come ha una yieldche lo ferma, ma non sono molto bravo con Python
Downgoat

Downgoat è corretto: utilizza una funzione di generatore .
Mego,

1
Ho scritto tutto il codice, non ho esaminato la tua implementazione tranne la pparte
acrolith,

3

Python 3.5, 278 263 byte:

import decimal,re;decimal.getcontext().prec=int(input());D=decimal.Decimal;a=p=1;b,t=1/D(2).sqrt(),1/D(4)
for i in[1]*50:z=(a+b)/2;b=(a*b).sqrt();t-=p*(a-z)**2;a=z;p*=2;pi=(z*2)**2/(4*t);i=0;C=lambda r:re.search(r'(\d)\1{%s}'%r,str(pi))
while C(i):print(C(i));i+=1

Questo accetta ncome input per le prime ncifre di πe quindi emette i membri della sequenza in quelle prime ncifre. Ora, questo utilizza il modulo decimale incorporato di Python per andare oltre i limiti in virgola mobile di Python, e quindi imposta la precisione, o epsilon, su qualsiasi input dell'utente. Quindi, per calcolare π, questo passa attraverso 50 iterazioni usando l' algoritmo Gausse-Legendre efficiente , dal momento che l'algoritmo sembra raddoppiare il numero di cifre corrette ogni volta, e quindi, in 50 iterazioni, possiamo ottenere 2^50o 1,125,899,906,842,624correggere cifre. Alla fine, dopo aver eseguito i calcoli, utilizza un'espressione regolare con formattazione di stringa in un whileciclo per trovare e stamparere abbina gli oggetti (che spero vada bene) per tutte le cifre continue e ricorrenti 1 cifra in più rispetto alla precedente iterazione attraverso il ciclo.

Sono stato in grado di utilizzare questo algoritmo per calcolare con successo e con precisione πfino a 10,000,000(dieci milioni) cifre, che sono state completate in circa 4 ore e 12 minuti. Il seguente è stato l'output finale:

<_sre.SRE_Match object; span=(0, 1), match='3'>
<_sre.SRE_Match object; span=(25, 27), match='33'>
<_sre.SRE_Match object; span=(154, 157), match='111'>
<_sre.SRE_Match object; span=(763, 767), match='9999'>
<_sre.SRE_Match object; span=(763, 768), match='99999'>
<_sre.SRE_Match object; span=(763, 769), match='999999'>
<_sre.SRE_Match object; span=(710101, 710108), match='3333333'> 

Quindi, posso affermare con certezza che l'ottavo numero della sequenza non si verifica nemmeno entro i primi 10 milioni di cifre! πè un numero casuale ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.