Python 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 10,000 หลักเสร็จในเวลาประมาณ 2 วินาทีด้วย PyPy 5.3
ตัวอย่างการใช้งาน
$ 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 มีหน่วยความจำไม่เพียงพอในระบบของฉันหลังจาก 100 ล้านหลัก แต่ Ramanujan ทำให้ไปถึง 400 ล้านในเวลาเพียง 38 นาที ฉันคิดว่านี่เป็นอีกกรณีหนึ่งที่มีอัตราการเติบโตที่ช้าลงของเงื่อนไขในท้ายที่สุดชนะอย่างน้อยในระบบที่มีทรัพยากร จำกัด
ตัวอย่างการใช้งาน
$ 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
เครื่องกำเนิดที่ไม่ จำกัด ได้เร็วกว่า
การใช้การอ้างอิงที่ระบุในคำอธิบายปัญหาน่าสนใจ โดยจะใช้เครื่องกำเนิดไฟฟ้ามากมายที่นำมาโดยตรงจากกระดาษUnbounded หัวจุกอัลกอริทึมสำหรับตัวเลขของพี่ การใช้งานที่ให้ไว้เป็น "จงใจปิดบัง" ดังนั้นฉันจึงตัดสินใจที่จะทำให้การใช้งานใหม่ของทั้งสามขั้นตอนวิธีการระบุไว้โดยผู้เขียนโดยไม่ต้องทำให้งงงวยโดยเจตนา ฉันได้เพิ่มนอกจากนี้ยังเป็นหนึ่งในสี่บนพื้นฐานของRamanujan #
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 รายการ: การใช้งานอ้างอิงสองรายการที่จัดทำโดยผู้แต่ง (เขียนแทน_ref
) และสี่คำที่คำนวณเป็นแบตช์สร้างตัวเลขหลายหลักพร้อมกัน ( _md
) การใช้งานทั้งหมดได้รับการยืนยันถึง 100,000 หลัก เมื่อเลือกขนาดแบทช์ฉันเลือกค่าที่ค่อยๆลดความแม่นยำลงตามเวลา ตัวอย่างเช่นg1_md
สร้าง 10 หลักต่อชุดพร้อม 33 ซ้ำ อย่างไรก็ตามสิ่งนี้จะสร้างตัวเลขที่ถูกต้อง ~ 9.93 เท่านั้น เมื่อความแม่นยำหมดสภาพการตรวจสอบจะล้มเหลวการทริกเกอร์ชุดพิเศษที่จะทำงาน สิ่งนี้ดูเหมือนว่าจะมีประสิทธิภาพมากกว่าความแม่นยำที่ช้าลงอย่างเห็นได้ชัดเมื่อเวลาผ่านไป
- G1 (Leibniz / ออยเลอร์)
ตัวแปรเสริมจะถูกเก็บไว้เป็นตัวแทนของ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
ที่การวนซ้ำที่สูงกว่าเงื่อนไขr
และt
ข้อกำหนดมีความสำคัญลดลงเรื่อย ๆ อย่างที่มันเป็นดีสำหรับ 100,000 หลักแรกดังนั้นมันอาจจะดีสำหรับทุกคน ผู้เขียนไม่ได้ใช้การอ้างอิง
- g3 (Gosper)
ผู้เขียนคาดเดาว่ามันไม่จำเป็นที่จะตรวจสอบว่าn
จะไม่เปลี่ยนแปลงในการทำซ้ำตามมาและมันทำหน้าที่เพียงเพื่อชะลออัลกอริทึม ในขณะที่อาจเป็นจริงเครื่องกำเนิดไฟฟ้าจะยึดตัวเลขที่ถูกต้องมากกว่า ~ 13% มากกว่าที่สร้างขึ้นในปัจจุบันซึ่งดูเหมือนจะค่อนข้างสิ้นเปลือง ฉันได้เพิ่มการตรวจสอบย้อนกลับและรอจนกว่าตัวเลข 50 หลักถูกต้องสร้างพวกเขาทั้งหมดในครั้งเดียวพร้อมประสิทธิภาพที่เพิ่มขึ้นอย่างเห็นได้ชัด
- g4 (Ramanujan 39)
คำนวณว่า
น่าเสียดายs
ไม่เป็นศูนย์เนื่องจากองค์ประกอบเริ่มต้น (3528 ÷) แต่ก็ยังเร็วกว่า g3 อย่างมาก การบรรจบกันคือ ~ 5.89 หลักต่อเทอม 3511 หลักถูกสร้างขึ้นในแต่ละครั้ง ถ้ามันค่อนข้างมากการสร้าง 271 หลักต่อ 46 การทำซ้ำก็เป็นตัวเลือกที่ดีเช่นกัน
การกำหนดเวลา
ถ่ายในระบบของฉันเพื่อการเปรียบเทียบเท่านั้น เวลามีการระบุไว้ในไม่กี่วินาที หากเวลาใช้เวลานานกว่า 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
คือ 235x เร็วกว่าการg3_ref
ใส่ที่ 500,000 เลขหลัก ที่กล่าวว่ายังคงมีค่าใช้จ่ายที่สำคัญในการสตรีมตัวเลขด้วยวิธีนี้ การคำนวณตัวเลขทั้งหมดโดยตรงโดยใช้ Ramanujan 39 ( แหล่งไพ ธ อน ) นั้นเร็วประมาณ 10 เท่า
ทำไมไม่ Chudnovsky
อัลกอริทึมของ Chudnovsky นั้นต้องการสแควร์รูทที่มีความแม่นยำเต็มรูปแบบซึ่งฉันก็ไม่แน่ใจว่าจะใช้งานได้จริงหรือไม่ Ramanujan 39 ค่อนข้างพิเศษในเรื่องนี้ อย่างไรก็ตามวิธีการนี้ดูเหมือนว่าอาจเอื้อต่อสูตรที่เหมือน Machin เช่นที่ใช้โดย y-cruncher เพื่อที่จะได้เป็นสถานที่ที่ควรค่าแก่การสำรวจ