#
# pi.py - Calculate Pi
#
import sys
import math
import gmpy2
from gmpy2 import mpfr
from gmpy2 import mpz
#
# Global Variables
#
count = 0
total = 0
old_p = 0
#
# Show Progress
#
def progress():
global count, old_p, total
p = int(math.floor(1000*count/total+0.5))
if (p > old_p):
old_p = p
g = int(math.floor(72.5*count/total+0.5))
for c in range(72):
if (c<g):
print("H", sep="", end="")
else:
print("-", sep="", end="")
print(" ", p/10, "%\r", sep="", end="", flush=True)
if (count == total):
print("\n", sep="", end="")
#
# Write digit string
#
def write_string(digit_string):
fd = open("pi-py.txt", mode="w")
fd.write(" pi = ")
for c in range(len(digit_string)):
if ((c != 1) and (c % 50 == 1)):
fd.write("\t")
fd.write(digit_string[c])
if (c == 0):
fd.write(".")
elif ((c % 1000) == 0):
fd.write(" << ")
fd.write(str(c))
fd.write("\r\n")
elif ((c % 500) == 0):
fd.write(" <\r\n")
elif ((c % 50) == 0):
fd.write("\r\n")
elif ((c % 5) == 0):
fd.write(" ")
# Final new-line
if ((c%50) != 0):
fd.write("\r\n")
fd.close()
#
# Recursive funcion.
#
def s(a, b, max):
global count
m = math.ceil((a + b) / 2)
if (b - a == 1):
if (a == 0):
r = 120 # 6!
q = mpz(640320**3)
p = gmpy2.sub( gmpy2.mul(q, 13591409),
gmpy2.mul(r, 13591409+545140134) )
else:
r = mpz(8 * (a*6+1) * (a*6+3) * (a*6+5))
q = mpz((b*640320)**3)
if ((b%2) == 0):
p = gmpy2.mul(mpz(13591409 + b*545140134), r)
else:
p = gmpy2.mul(mpz(-13591409 - b*545140134), r)
else:
p1, q1, r1 = s(a, m, max)
p2, q2, r2 = s(m, b, max)
# Merge
p = gmpy2.add( gmpy2.mul(p1, q2), gmpy2.mul(p2, r1) )
q = gmpy2.mul(q1, q2)
if (b != max):
r = gmpy2.mul(r1, r2)
else:
r = 0
count += 1
progress()
return p, q, r;
#
# Calculate e
#
def calc_pi(digits):
global total
d = digits+1
n_terms = math.ceil(d*math.log(10)/(3*math.log(53360)))
precision = math.ceil(d * math.log2(10)) + 4;
print("d = ", d, ", n = ", n_terms, ", precision = ", precision, sep="")
gmpy2.get_context().precision = precision
gmpy2.get_context().emax = 1000000000000;
print("Real precision =", gmpy2.get_context().precision)
total = n_terms * 2 - 1 # Max progress
p, q, r = s(0, n_terms, n_terms)
q = gmpy2.mul(q, 426880)
print("Recursion done. Processing division.")
ef = gmpy2.div(q, p)
ef = gmpy2.mul(ef, gmpy2.sqrt(10005))
print("Division done. Converting to digits.")
estr, exp, prec = mpfr.digits(ef)
estr = estr[0:d]
print("Writing to file.")
write_string(estr);
#
# main program
#
argc = len(sys.argv)
if (argc >= 2):
digits = int(sys.argv[1])
else:
digits = 100000
calc_pi(digits)
# End of pi.py
IwojICBwaS5weSAtIENhbGN1bGF0ZSBQaQojCmltcG9ydCBzeXMKaW1wb3J0IG1hdGgKaW1wb3J0IGdtcHkyCmZyb20gZ21weTIgaW1wb3J0IG1wZnIKZnJvbSBnbXB5MiBpbXBvcnQgbXB6CgojCiMgR2xvYmFsIFZhcmlhYmxlcwojCmNvdW50ID0gMAp0b3RhbCA9IDAKb2xkX3AgPSAwCgojCiMgU2hvdyBQcm9ncmVzcwojCmRlZiBwcm9ncmVzcygpOgogICAgICAgIGdsb2JhbCBjb3VudCwgb2xkX3AsIHRvdGFsCgogICAgICAgIHAgPSBpbnQobWF0aC5mbG9vcigxMDAwKmNvdW50L3RvdGFsKzAuNSkpCiAgICAgICAgaWYgKHAgPiBvbGRfcCk6CiAgICAgICAgICAgICAgICBvbGRfcCA9IHAKICAgICAgICAgICAgICAgIGcgPSBpbnQobWF0aC5mbG9vcig3Mi41KmNvdW50L3RvdGFsKzAuNSkpCiAgICAgICAgICAgICAgICBmb3IgYyBpbiByYW5nZSg3Mik6CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjPGcpOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50KCJIIiwgc2VwPSIiLCBlbmQ9IiIpCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnQoIi0iLCBzZXA9IiIsIGVuZD0iIikKICAgICAgICAgICAgICAgIHByaW50KCIgIiwgcC8xMCwgIiVcciIsIHNlcD0iIiwgZW5kPSIiLCBmbHVzaD1UcnVlKQoKICAgICAgICBpZiAoY291bnQgPT0gdG90YWwpOgogICAgICAgICAgICAgICAgcHJpbnQoIlxuIiwgc2VwPSIiLCBlbmQ9IiIpCgojCiMgV3JpdGUgZGlnaXQgc3RyaW5nCiMKZGVmIHdyaXRlX3N0cmluZyhkaWdpdF9zdHJpbmcpOgogICAgICAgIGZkID0gb3BlbigicGktcHkudHh0IiwgbW9kZT0idyIpCgogICAgICAgIGZkLndyaXRlKCIgcGkgPSAiKQogICAgICAgIGZvciBjIGluIHJhbmdlKGxlbihkaWdpdF9zdHJpbmcpKToKICAgICAgICAgICAgICAgIGlmICgoYyAhPSAxKSBhbmQgKGMgJSA1MCA9PSAxKSk6CiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcdCIpCiAgICAgICAgICAgICAgICBmZC53cml0ZShkaWdpdF9zdHJpbmdbY10pCiAgICAgICAgICAgICAgICBpZiAoYyA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIi4iKQogICAgICAgICAgICAgICAgZWxpZiAoKGMgJSAxMDAwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiA8PCAiKQogICAgICAgICAgICAgICAgICAgICAgICBmZC53cml0ZShzdHIoYykpCiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcclxuIikKICAgICAgICAgICAgICAgIGVsaWYgKChjICUgNTAwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiA8XHJcbiIpCiAgICAgICAgICAgICAgICBlbGlmICgoYyAlIDUwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIlxyXG4iKQogICAgICAgICAgICAgICAgZWxpZiAoKGMgJSA1KSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiAiKQoKICAgICAgICAjIEZpbmFsIG5ldy1saW5lCiAgICAgICAgaWYgKChjJTUwKSAhPSAwKToKICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcclxuIikKCiAgICAgICAgZmQuY2xvc2UoKQoKIwojIFJlY3Vyc2l2ZSBmdW5jaW9uLgojCmRlZiBzKGEsIGIsIG1heCk6CiAgICAgICAgZ2xvYmFsIGNvdW50CgogICAgICAgIG0gPSBtYXRoLmNlaWwoKGEgKyBiKSAvIDIpCgogICAgICAgIGlmIChiIC0gYSA9PSAxKToKICAgICAgICAgICAgICAgIGlmIChhID09IDApOgogICAgICAgICAgICAgICAgICAgICAgICByID0gMTIwICAgICAgICAgIyA2IQogICAgICAgICAgICAgICAgICAgICAgICBxID0gbXB6KDY0MDMyMCoqMykKICAgICAgICAgICAgICAgICAgICAgICAgcCA9IGdtcHkyLnN1YiggZ21weTIubXVsKHEsIDEzNTkxNDA5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbXB5Mi5tdWwociwgMTM1OTE0MDkrNTQ1MTQwMTM0KSApCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICByID0gbXB6KDggKiAoYSo2KzEpICogKGEqNiszKSAqIChhKjYrNSkpCiAgICAgICAgICAgICAgICAgICAgICAgIHEgPSBtcHooKGIqNjQwMzIwKSoqMykKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKChiJTIpID09IDApOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPSBnbXB5Mi5tdWwobXB6KDEzNTkxNDA5ICsgYio1NDUxNDAxMzQpLCByKQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPSBnbXB5Mi5tdWwobXB6KC0xMzU5MTQwOSAtIGIqNTQ1MTQwMTM0KSwgcikKICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcDEsIHExLCByMSA9IHMoYSwgbSwgbWF4KQogICAgICAgICAgICAgICAgcDIsIHEyLCByMiA9IHMobSwgYiwgbWF4KQoKICAgICAgICAgICAgICAgICMgTWVyZ2UKICAgICAgICAgICAgICAgIHAgPSBnbXB5Mi5hZGQoIGdtcHkyLm11bChwMSwgcTIpLCBnbXB5Mi5tdWwocDIsIHIxKSApCiAgICAgICAgICAgICAgICBxID0gZ21weTIubXVsKHExLCBxMikKCiAgICAgICAgICAgICAgICBpZiAoYiAhPSBtYXgpOgogICAgICAgICAgICAgICAgICAgICAgICByID0gZ21weTIubXVsKHIxLCByMikKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAwCgogICAgICAgIGNvdW50ICs9IDEKICAgICAgICBwcm9ncmVzcygpCgogICAgICAgIHJldHVybiBwLCBxLCByOwoKIwojIENhbGN1bGF0ZSBlCiMKZGVmIGNhbGNfcGkoZGlnaXRzKToKICAgICAgICBnbG9iYWwgdG90YWwKCiAgICAgICAgZCA9IGRpZ2l0cysxCiAgICAgICAgbl90ZXJtcyA9IG1hdGguY2VpbChkKm1hdGgubG9nKDEwKS8oMyptYXRoLmxvZyg1MzM2MCkpKQogICAgICAgIHByZWNpc2lvbiA9IG1hdGguY2VpbChkICogbWF0aC5sb2cyKDEwKSkgKyA0OwogICAgICAgIHByaW50KCJkID0gIiwgZCwgIiwgbiA9ICIsIG5fdGVybXMsICIsIHByZWNpc2lvbiA9ICIsIHByZWNpc2lvbiwgc2VwPSIiKQoKICAgICAgICBnbXB5Mi5nZXRfY29udGV4dCgpLnByZWNpc2lvbiA9IHByZWNpc2lvbgogICAgICAgIGdtcHkyLmdldF9jb250ZXh0KCkuZW1heCA9IDEwMDAwMDAwMDAwMDA7CiAgICAgICAgcHJpbnQoIlJlYWwgcHJlY2lzaW9uID0iLCBnbXB5Mi5nZXRfY29udGV4dCgpLnByZWNpc2lvbikKICAgICAgICB0b3RhbCA9IG5fdGVybXMgKiAyIC0gMSAgICAgICAgICMgTWF4IHByb2dyZXNzCgogICAgICAgIHAsIHEsIHIgPSBzKDAsIG5fdGVybXMsIG5fdGVybXMpCgogICAgICAgIHEgPSBnbXB5Mi5tdWwocSwgNDI2ODgwKQoKICAgICAgICBwcmludCgiUmVjdXJzaW9uIGRvbmUuIFByb2Nlc3NpbmcgZGl2aXNpb24uIikKICAgICAgICBlZiA9IGdtcHkyLmRpdihxLCBwKQoKICAgICAgICBlZiA9IGdtcHkyLm11bChlZiwgZ21weTIuc3FydCgxMDAwNSkpCgogICAgICAgIHByaW50KCJEaXZpc2lvbiBkb25lLiBDb252ZXJ0aW5nIHRvIGRpZ2l0cy4iKQogICAgICAgIGVzdHIsIGV4cCwgcHJlYyA9IG1wZnIuZGlnaXRzKGVmKQogICAgICAgIGVzdHIgPSBlc3RyWzA6ZF0KICAgICAgICBwcmludCgiV3JpdGluZyB0byBmaWxlLiIpCiAgICAgICAgd3JpdGVfc3RyaW5nKGVzdHIpOwoKIwojICBtYWluIHByb2dyYW0KIwphcmdjID0gbGVuKHN5cy5hcmd2KQppZiAoYXJnYyA+PSAyKToKICAgICAgICBkaWdpdHMgPSBpbnQoc3lzLmFyZ3ZbMV0pCmVsc2U6CiAgICAgICAgZGlnaXRzID0gMTAwMDAwCgpjYWxjX3BpKGRpZ2l0cykKCiMgRW5kIG9mIHBpLnB5Cg==