Pi의 자릿수


13

당신의 목표는 엄격하게 증가하는 연속적인 동일한 숫자 pi (π)의 시퀀스를 출력하는 것입니다. 시퀀스의 각 항은 이전보다 한 자리 더 길어야합니다. 따라서 3(0 번째 자릿수 pi)는 숫자의 런이 처음 발생하는 길이입니다 (길이 1). 다음에는 33(pi의 24와 25의 숫자)입니다. 물론,이 순서는 pi의 숫자가 10의 밑 이되어야 합니다.

지금까지 알려진 것 , 처음 6 개는 모두 처음 800 자리 내에 나타납니다.

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

연속 된 9 개는 모두 같은 런에서 함께 발생하므로 다음으로 큰 런이 1000 개의 연속 0s 인 경우 시퀀스의 여러 항을 채 웁니다 .

프로그램에서 더 이상 용어를 찾지 못했습니다. 첫 50000 자리 이상의 용어가 더 이상 없다는 것을 알고 있습니다. 내 프로그램이 500000 자리 숫자로 너무 오래 걸렸으므로 포기했습니다.

참조 구현

당신은 할 수있다:

  • 시퀀스를 영원히 출력
  • 정수를 취하여 시퀀스에서 n첫 번째 n숫자를 찾으십시오.
  • 정수를 취하여 pi n의 첫 번째 n숫자에 포함 된 시퀀스의 숫자를 찾으십시오 .

코드가 수행하는 코드를 지정하십시오. 숫자 n는 0 또는 1입니다.

이 mathoverflow 질문에서 영감을 얻었습니다 .


1
관련 -9s의 실행은 많은 답변에 두통을 일으켰습니다 : P
Mego

빈 시퀀스로 출력을 시작할 수 있습니까?
LegionMammal978

2
또한 시퀀스의 다음 항은 10 ^ -710100에서 10 ^ -710106 사이의 숫자로 3333333 인 것으로 나타납니다. n = 8 의 값 은 처음 5 000 000 자리에 나타나지 않습니다.
LegionMammal978

4
두 개의 용어 : 10 ^ -22931745에서 10 ^ -22931752까지의 44444444 및 10 ^ -24658601에서 10 ^ -24658609까지의 777777777 n = 10 의 값 은 처음 100 000 자리에 나타나지 않습니다.
LegionMammal978

1
한 번 더 용어 : 10666-386980412의 6666666666. 11 번째 용어는 처음 2000000 자리에 나타나지 않습니다.
primo

답변:


5

Mathematica, 85 바이트

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

익명의 기능. n 을 입력으로 취하고 시퀀스의 요소 를 π 의 처음 n 자리로 반환합니다 . 출력 형식은 {0, 3, 33, 111, ...}입니다.


4

파이썬 2, 110 바이트

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

확인할 최대 자릿수는 stdin에서 가져온 것입니다. PyPy 5.3에서는 10,000 자리가 약 2 초 안에 끝납니다.

샘플 사용법

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

유용한 것

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

이를 위해 Chudnovsky에서 Ramanujan 39로 전환했습니다. Chudnovsky는 1 억 자릿수 직후에 내 시스템의 메모리가 부족했지만 Ramanujan은 약 38 분 만에 4 억 개의 메모리를 만들었습니다. 나는 이것이 최소한 자원이 제한된 시스템에서 결국 성장률이 더 느리다는 것이 또 하나의 사례라고 생각합니다.

샘플 사용법

$ 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

더 빠른 무제한 생성기

문제 설명에 주어진 참조 구현이 흥미 롭습니다. Pi의 Digits에 대한 Unbounded Spigot Algorims 논문에서 직접 가져온 무제한 생성기를 사용합니다 . 저자에 따르면, 제공된 구현은 "의도적으로 모호하다"며, 의도적으로 난독 화없이 저자가 제시 한 세 가지 알고리즘을 모두 새로 구현하기로 결정했습니다. 또한 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)

노트

위의 6 가지 구현은 저자가 제공 한 2 개의 참조 구현 (으로 표시 _ref)과 4 개는 일괄 적으로 용어를 계산하여 한 번에 여러 자릿수를 생성하는 것입니다 ( _md). 모든 구현은 100,000 자리로 확인되었습니다. 배치 크기를 선택할 때 시간이 지남에 따라 천천히 정밀도가 떨어지는 값을 선택했습니다. 예를 들어, g1_md배치 당 10 자리를 생성하고 33 회 반복합니다. 그러나 이것은 ~ 9.93 정확한 숫자 만 생성합니다. 정밀도가 떨어지면 검사 조건이 실패하고 추가 배치가 실행됩니다. 이것은 시간이 지남에 따라 천천히 불필요한 추가 정밀도보다 더 성능이 좋은 것으로 보입니다.

  • g1 (Leibniz / Euler)를 나타내는
    추가 변수 j가 유지됩니다 2*i+1. 저자는 참조 구현에서 동일한 작업을 수행합니다. 계산 n이의 현재 값을 사용하기 때문에 별도로하는 것은 훨씬 간단 (덜 모호한)이며 q, r그리고 t오히려 다음보다.
  • g2 (황색)
    수표 n == q/s가 꽤 느슨합니다. 즉 읽어야 n == (q*(k+2*j+4)+r)/(s*(k+2*j+4)+t)j이다 2*i-1하고 k있다 i*i. 반복이 높을수록 rt용어의 중요성이 점점 줄어 듭니다. 있는 그대로, 처음 100,000 자리에 적합하므로 아마 모두에게 좋습니다. 저자는 참조 구현을 제공하지 않습니다.
  • g3 (Gosper)
    저자 n는 후속 반복에서 변경되지 않는지 확인할 필요 가 없으며 알고리즘 속도를 늦추는 역할 만한다고 추측합니다 . 아마도 사실이지만 발전기는 현재 생성 된 것보다 ~ 13 % 더 정확한 자릿수를 유지하고 있습니다. 체크 인을 다시 추가하고 50 자리가 올 때까지 기다렸다가 한 번에 모두 생성하여 눈에 띄는 성능을 얻습니다.
  • g4 (Ramanujan 39) 불행히도
    계산 되었으나 초기 (3528 ÷) 구성으로 인해 0으로 끝나지 않지만 여전히 g3보다 훨씬 빠릅니다. 수렴은 용어 당 ~ 5.89 자리이며 한 번에 3511 자리가 생성됩니다. 그것이 조금 많으면 46 반복마다 271 자리를 생성하는 것도 괜찮은 선택입니다.

    s

타이밍

비교 목적으로 만 내 시스템에서 촬영했습니다. 시간은 초 단위로 나열됩니다. 타이밍이 10 분 이상 걸리면 더 이상 테스트를 실행하지 않았습니다.

            |  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 

느린 수렴 속도에도 불구하고 g2결국에는 추월 하는 것이 흥미 롭습니다 g3. 나는 이것이 피연산자가 상당히 느린 속도로 성장하여 장기적으로 승리했기 때문이라고 생각합니다. 가장 빠른 g4_md임 포지션 g3_ref은 500,000 자리 의 임 포지션보다 약 235 배 빠릅니다 . 즉, 이런 방식으로 스트리밍 자릿수에 여전히 상당한 오버 헤드가 있습니다. Ramanujan 39 ( python source )를 사용하여 직접 모든 숫자를 계산하는 것은 약 10 배 빠릅니다.

Chudnovsky는 왜 안됩니까?

Chudnovsky 알고리즘에는 완전 정밀 제곱근이 필요합니다. 정확히 제곱근을 사용한다고 가정합니다. Ramanujan 39는 이와 관련하여 다소 특별합니다. 그러나이 방법은 y-cruncher에서 사용하는 것과 같은 Machin과 같은 공식에 도움이 될 것 같으므로 탐색 할 가치가 있습니다.


TIL Ideone은 Pypy를 지원합니다. 그래서 두 번째 프로그램은 속도를 위해 만들어 졌습니까?
mbomb007

@ mbomb007 "두 번째 프로그램은 속도를 위해 만들어 졌습니까?" 그것은. 도전 과제는 가장 빠른 코드 만큼이나 흥미 로웠을 것 입니다.
primo

같은. 나는 둘 다 고려했다. 사람들이 다른 태그로 다시 게시하는 것에 대한 느낌. OEIS (이 시퀀스를 포함하지 않음)에 추가되는 경우 더 유용 할 수 있습니다.
mbomb007

3

하스켈, 231 바이트

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) 

이것은 Jeremy Gibbons, 2004 의 Pi의 Digits에 대해 Unbounded Spigot Algorims를 사용합니다 p. 결과는 입니다. 기술적으로 무한 출력 시퀀스를 지원해야하지만 시간이 오래 걸릴 수 있습니다 (메모리에 의해 제한됨).


3

파이썬 2, 298 바이트

pi를 생성하는 코드는 OP의 구현에서 가져옵니다.

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

파이썬에서 골프를 치기위한 첫 번째 시도. 시퀀스를 영원히 출력합니다.


계산 방법을 설명해 주 π시겠습니까? 당신은 물론 파이를 계산합니까?
R. Kap

지금 테스트 할 수는 없지만 π영원히 계산하지 않습니까?
Yytsi

@TuukkaX는 그것이 yield멈추는 것처럼 보이지 않지만 파이썬에는 능숙하지 않습니다
Downgoat

다운 염소는 정확 합니다 . 생성기 기능을 사용 합니다 .
Mego

1
모든 코드를 작성했습니다. p부분을 제외하고 구현을 보지 않았습니다
acrolith

3

Python 3.5, 278263 바이트 :

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

이것은 n첫 번째 n자리의 입력 π으로 받아 시퀀스의 멤버를 첫 번째 자리 로 출력합니다 n. 이제 이것은 파이썬의 내장 십진 모듈 을 사용하여 파이썬의 부동 소수점 한계를 뛰어 넘고 정밀도 또는 엡실론을 많은 사용자 입력으로 설정합니다. 그런 다음 계산하기 π위해 효율적인 Gausse-Legendre 알고리즘을 사용하여 50 회 반복 합니다. 알고리즘은 매번 올바른 자릿수를 두 배로 늘리기 때문에 50 번 반복하면 최대 자릿수 2^50또는 1,125,899,906,842,624올바른 자릿수 를 얻을 수 있습니다 . 마지막으로 계산이 끝나면 while루프 에서 문자열 형식의 정규식을 사용 하여 찾아서 인쇄합니다.re 루프를 통해 이전 반복에서보다 1 자릿수의 모든 연속적인 반복 자릿수에 대해 객체를 일치시킵니다.

이 알고리즘을 사용하여 π최대 10,000,000(천만) 자릿수 를 성공적으로 정확하게 계산할 수 있었으며 완료 하는 데 약 4 시간 12 분이 걸렸습니다. 최종 결과는 다음과 같습니다.

<_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'> 

따라서 시퀀스의 8 번째 숫자는 처음 천만 자리 안에도 나타나지 않는다고 자신있게 말할 수 있습니다! π하나의 난수입니다 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.