Chạy chữ số trong Pi


13

Mục tiêu của bạn là đưa ra chuỗi tăng dần các chữ số pi (π) liên tiếp, giống hệt nhau. Mỗi thuật ngữ trong chuỗi phải dài hơn một chữ số so với trước đó. Vì vậy 3(chữ số 0 của số pi) là lần đầu tiên xuất hiện một chữ số (độ dài 1). Tiếp theo xảy ra là 33(chữ số 24 và 25 của pi). Tất nhiên, chuỗi này yêu cầu các chữ số của pi nằm trong cơ sở 10 .

Những cái đã biết cho đến nay và sáu số đầu tiên đều xuất hiện trong 800 chữ số đầu tiên:

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

Lưu ý rằng tất cả các số liên tiếp xảy ra cùng nhau, trong cùng một lần chạy, vì vậy nếu lần chạy lớn hơn tiếp theo bạn thấy xảy ra là 1000 0giây liên tiếp , điều này sẽ điền vào nhiều điều khoản của chuỗi.

Tôi không tìm thấy bất kỳ điều khoản nào nữa với chương trình của tôi. Tôi biết không có nhiều điều khoản trong 50000 chữ số đầu tiên trở lên. Chương trình của tôi mất quá nhiều thời gian với 500000 chữ số, vì vậy tôi đã từ bỏ.

Thực hiện tham khảo

Bạn có thể:

  • Xuất ra chuỗi mãi mãi
  • Lấy một số nguyên nvà tìm các nsố đầu tiên trong chuỗi
  • Lấy một số nguyên nvà tìm các số trong dãy chứa trong các nchữ số đầu tiên của pi.

Hãy chắc chắn để xác định mã nào của bạn làm. Số ncó thể bằng 0 hoặc một chỉ mục.

Lấy cảm hứng từ câu hỏi mathoverflow này .


1
Liên quan - việc chạy 9 giây gây đau đầu cho nhiều câu trả lời: P
Mego

Bạn có được phép bắt đầu đầu ra với chuỗi trống không?
LegionMammal978

2
Ngoài ra, thuật ngữ tiếp theo của chuỗi dường như là 3333333 ở các chữ số 10 ^ -710100 đến 10 ^ -710106. Giá trị cho n = 8 không xuất hiện trong 5 000 000 chữ số đầu tiên.
LegionMammal978

4
Hai thuật ngữ nữa: 44444444 ở các chữ số 10 ^ -22931745 đến 10 ^ -22931752 và 777777777 ở các chữ số 10 ^ -24658601 đến 10 ^ -24658609. Giá trị cho n = 10 không xuất hiện trong 100 000 000 chữ số đầu tiên.
LegionMammal978

1
Thêm một nhiệm kỳ: 6666666666 tại 10 ^ -386980412. Thuật ngữ thứ 11 không xuất hiện trong 2 000 000 000 chữ số đầu tiên.
primo

Câu trả lời:


5

Toán học, 85 byte

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

Chức năng ẩn danh. Lấy n làm đầu vào và trả về các phần tử của chuỗi trong n chữ số đầu tiên của π. Đầu ra ở dạng {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

Số chữ số tối đa để kiểm tra được lấy từ stdin. 10.000 chữ số kết thúc sau khoảng 2 giây với PyPy 5.3.

Sử dụng mẫu

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

Một vài thứ hữu ích

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

Tôi đã chuyển từ Chudnovsky sang Ramanujan 39 cho việc này. Chudnovsky đã hết bộ nhớ trên hệ thống của tôi ngay sau 100 triệu chữ số, nhưng Ramanujan đã đạt được con số 400 triệu, chỉ trong khoảng 38 phút. Tôi nghĩ rằng đây là một trường hợp khác là tốc độ tăng trưởng chậm hơn của các điều khoản cuối cùng, ít nhất là trên một hệ thống có nguồn lực hạn chế.

Sử dụng mẫu

$ 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

Máy phát điện không giới hạn nhanh hơn

Việc thực hiện tham chiếu được đưa ra trong mô tả vấn đề là thú vị. Nó sử dụng một trình tạo không giới hạn, được lấy trực tiếp từ thuật toán Spigot không giới hạn trên giấy cho các chữ số của Pi . Theo tác giả, các triển khai được cung cấp là "cố tình che khuất", vì vậy tôi quyết định thực hiện các triển khai mới của cả ba thuật toán được liệt kê bởi tác giả, mà không cố tình che giấu. Tôi cũng đã thêm một phần tư, dựa trên 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)

Ghi chú

Trên đây là 6 triển khai: hai triển khai tham chiếu được cung cấp bởi tác giả (ký hiệu _ref) và bốn triển khai tính toán các thuật ngữ theo lô, tạo ra nhiều chữ số cùng một lúc ( _md). Tất cả các triển khai đã được xác nhận đến 100.000 chữ số. Khi chọn kích thước lô, tôi chọn các giá trị từ từ mất độ chính xác theo thời gian. Ví dụ: g1_mdtạo 10 chữ số mỗi lô, với 33 lần lặp. Tuy nhiên, điều này sẽ chỉ tạo ra ~ 9,93 chữ số chính xác. Khi độ chính xác hết, điều kiện kiểm tra sẽ thất bại, kích hoạt một lô bổ sung được chạy. Điều này dường như được thực hiện nhiều hơn là từ từ tăng thêm, độ chính xác không cần thiết theo thời gian.

  • g1 (Leibniz / Euler)
    Một biến phụ jđược giữ, đại diện 2*i+1. Các tác giả làm tương tự trong việc thực hiện tham khảo. Tính toán nriêng biệt đơn giản hơn nhiều (và ít tối nghĩa hơn), bởi vì nó sử dụng các giá trị hiện tại của q, rt, thay vì tiếp theo.
  • g2 (Lambert)
    Việc kiểm tra n == q/sđược thừa nhận khá lỏng lẻo. Đó là nên đọc n == (q*(k+2*j+4)+r)/(s*(k+2*j+4)+t), nơi j2*i-1ki*i. Ở các lần lặp cao hơn, các thuật ngữ rtngày càng trở nên ít quan trọng hơn. Như vậy, nó tốt cho 100.000 chữ số đầu tiên, vì vậy nó có thể tốt cho tất cả. Tác giả cung cấp không thực hiện tham khảo.
  • g3 (Gosper)
    Tác giả phỏng đoán rằng không cần thiết phải kiểm tra xem nó nsẽ không thay đổi trong các lần lặp lại tiếp theo hay không và nó chỉ phục vụ để làm chậm thuật toán. Mặc dù có lẽ đúng, nhưng trình tạo này đang giữ các chữ số chính xác hơn ~ 13% so với hiện tại, điều này có vẻ hơi lãng phí. Tôi đã thêm kiểm tra lại và đợi cho đến khi 50 chữ số chính xác, tạo ra tất cả chúng cùng một lúc, với hiệu suất đáng chú ý.
  • g4 (Ramanujan 39) Được
    tính là

    Thật không may, skhông bằng không, do thành phần ban đầu (3528), nhưng nó vẫn nhanh hơn đáng kể so với g3. Hội tụ là ~ 5,89 chữ số cho mỗi thuật ngữ, 3511 chữ số được tạo tại một thời điểm. Nếu đó là một chút nhiều, tạo ra 271 chữ số trên 46 lần lặp cũng là một lựa chọn hợp lý.

Thời gian

Lấy trên hệ thống của tôi, chỉ nhằm mục đích so sánh. Thời gian được liệt kê trong vài giây. Nếu thời gian kéo dài hơn 10 phút, tôi đã không chạy thêm bất kỳ bài kiểm tra nào.

            |  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 

Thật thú vị khi g2cuối cùng đã vượt qua g3, mặc dù tốc độ hội tụ chậm hơn. Tôi nghi ngờ điều này là do các toán hạng phát triển với tốc độ chậm hơn đáng kể, chiến thắng trong thời gian dài. g4_mdCấy ghép nhanh nhất là nhanh hơn khoảng 235 lần so với cấy ghép g3_reftrên 500.000 chữ số. Điều đó nói rằng, vẫn còn một chi phí đáng kể để truyền các chữ số theo cách này. Tính toán tất cả các chữ số trực tiếp bằng Ramanujan 39 ( nguồn python ) nhanh gấp khoảng 10 lần.

Tại sao không phải là Chudnovsky?

Thuật toán Chudnovsky yêu cầu một căn bậc hai chính xác đầy đủ, mà tôi thực sự không chắc chắn làm thế nào để làm việc - giả sử nó có thể là tất cả. Ramanujan 39 có phần đặc biệt về vấn đề này. Tuy nhiên, phương pháp này có vẻ có lợi cho các công thức giống Machin, chẳng hạn như các công thức được sử dụng bởi y-cruncher, vì vậy đó có thể là một con đường đáng để khám phá.


TIL Ideone hỗ trợ Pypy. Vì vậy, chương trình thứ 2 được xây dựng cho tốc độ?
mbomb007

@ mbomb007 "Vậy chương trình thứ 2 có được xây dựng cho tốc độ không?" Nó là. Tôi nghĩ rằng thách thức sẽ thú vị không kém mã nhanh nhất .
primo

Tương tự. Tôi đã xem xét cả hai. Idk mọi người cảm thấy thế nào về việc đăng lại dưới một thẻ khác. Nó có thể hữu ích hơn nếu được thêm vào OEIS (không chứa chuỗi này)
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) 

Điều này sử dụng các thuật toán Spigot không giới hạn cho các chữ số Pi của Jeremy Gibbons, 2004. Kết quả là p. Về mặt kỹ thuật, nó sẽ hỗ trợ các chuỗi đầu ra vô hạn, nhưng điều đó có thể mất một lúc (và bị giới hạn bởi bộ nhớ của bạn).


3

Python 2, 298 byte

Lưu ý, mã để tạo pi được lấy từ triển khai của 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

Nỗ lực đầu tiên của tôi khi chơi golf trong Python. Xuất ra chuỗi mãi mãi.


Bạn có thể vui lòng giải thích làm thế nào bạn tính toán πở đây? Bạn, tất nhiên, tính pi, phải không?
R. Kap

Không thể kiểm tra ngay bây giờ, nhưng bạn không tính toán πmãi mãi ở đó?
Yytsi

@TuukkaX không xuất hiện vì nó có một yieldđiểm dừng, nhưng tôi không giỏi lắm về trăn
Downgoat

Downgoat là chính xác - nó sử dụng chức năng tạo .
Mego

1
Tôi đã viết tất cả các mã, tôi đã không nhìn vào việc thực hiện của bạn ngoại trừ p phần
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

Điều này nhận nlàm đầu vào cho các nchữ số đầu tiên πvà sau đó đầu ra các thành viên của chuỗi trong các nchữ số đầu tiên đó . Bây giờ, điều này sử dụng mô-đun thập phân tích hợp của Python để vượt qua các giới hạn về dấu phẩy động của Python và sau đó đặt độ chính xác, hoặc epsilon, cho nhiều người dùng nhập vào. Sau đó, để tính toán π, điều này trải qua 50 lần lặp bằng thuật toán Gausse-Legendre hiệu quả , vì thuật toán dường như nhân đôi số chữ số chính xác mỗi lần, và do đó, trong 50 lần lặp, chúng ta có thể nhận được 2^50hoặc 1,125,899,906,842,624sửa các chữ số. Cuối cùng, sau khi tính toán xong, nó sử dụng một biểu thức chính quy với định dạng chuỗi trong một whilevòng lặp để tìm và inre đối tượng khớp (mà tôi hy vọng là ổn) cho tất cả các chữ số lặp lại liên tục, dài hơn 1 chữ số so với lần lặp trước thông qua vòng lặp.

Tôi đã có thể sử dụng thuật toán này để tính toán thành công và chính xác πtới 10,000,000(mười triệu) chữ số, mất khoảng 4 giờ 12 phút để hoàn thành. Sau đây là đầu ra cuối cùng:

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

Vì vậy, tôi có thể tự tin nói rằng số thứ 8 trong chuỗi thậm chí không xảy ra trong vòng 10 triệu chữ số đầu tiên! πlà một số ngẫu nhiên ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.