#!/usr/bin/env python3
#
# pi.py - Calculate Pi
#
import sys
import time
import math
import gmpy2
from gmpy2 import mpfr
from gmpy2 import mpz
#
# Global Variables
#
count = 0
total = 0
grad = 0
step = 0
#
# Show Progress
#
def progress_init(max):
global count, total, grad, step
total = max
count = 0
step = int(total / 1000)
grad = int(step / 2)
def progress():
global count, total, grad, step
if (count > grad):
grad += step
g = int(math.floor(72.5*count/total+0.5))
p = int(math.floor(1000.5*count/total+0.5))
msg = "H" * g + "-" * (72-g) + " " + str(p/10) + "%\r"
if (grad > total):
msg += "\n"
print(msg, sep="", end="", flush=True)
#
# Write digit string
#
def write_string(digit_string):
fd = open("pi-py.txt", mode="w")
fd.write(" pi = ")
fd.write(digit_string[0])
fd.write(".")
for c in range(1, len(digit_string), 50):
if (c != 1):
fd.write("\t")
fd.write(digit_string[c:c+50])
if ((c % 1000) == 951):
fd.write(" << ")
fd.write(str(c+49))
fd.write("\r\n")
elif ((c % 500) == 451):
fd.write(" <\r\n")
else:
fd.write("\r\n")
# Final new-line
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="")
print("gmpy2 version:", gmpy2.version())
print("MP version:", gmpy2.mp_version())
print("MPFR version:", gmpy2.mpfr_version())
max_precision = gmpy2.get_max_precision()
print("max_precision =", max_precision)
max_emax = gmpy2.get_emax_max()
print("max_emax =", max_emax)
if (max_precision < precision):
print("Error! Max precision is too small! Program terminated.")
return
gmpy2.get_context().precision = precision
gmpy2.get_context().emax = max_emax
print("Real precision = ", gmpy2.get_context().precision)
progress_init(n_terms * 2 - 1) # Initialize progress bar
# Recursion
start_time = time.monotonic_ns()
p, q, r = s(0, n_terms, n_terms)
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Recursion:", elapsed, "seconds.")
start_time = time.monotonic_ns()
q = gmpy2.mul(q, 426880)
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Multiply by 426880:", elapsed, "seconds.")
start_time = time.monotonic_ns()
pf = mpfr(p)
qf = mpfr(q)
ef = gmpy2.div(qf, pf)
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Grand Division:", elapsed, "seconds.")
start_time = time.monotonic_ns()
ef = gmpy2.mul(ef, gmpy2.sqrt(10005))
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Multiply by sqrt(10005):", elapsed, "seconds.")
# Convert to decimal digits
start_time = time.monotonic_ns()
estr, exp, prec = mpfr.digits(ef)
estr = estr[0:d]
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Convert to decimal digits:", elapsed, "seconds.")
# Write to file
start_time = time.monotonic_ns()
write_string(estr)
end_time = time.monotonic_ns()
elapsed = (end_time - start_time) / 1000000000
print("Write to file:", elapsed, "seconds.")
#
# main program
#
if __name__ == '__main__':
argc = len(sys.argv)
if (argc >= 2):
digits = int(sys.argv[1])
else:
digits = 100000
calc_pi(digits)
# End of pi.py
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwojCiMgIHBpLnB5IC0gQ2FsY3VsYXRlIFBpCiMKaW1wb3J0IHN5cwppbXBvcnQgdGltZQppbXBvcnQgbWF0aAppbXBvcnQgZ21weTIKZnJvbSBnbXB5MiBpbXBvcnQgbXBmcgpmcm9tIGdtcHkyIGltcG9ydCBtcHoKCiMKIyBHbG9iYWwgVmFyaWFibGVzCiMKY291bnQgICA9IDAKdG90YWwgICA9IDAKZ3JhZCAgICA9IDAKc3RlcCAgICA9IDAKCiMKIyBTaG93IFByb2dyZXNzCiMKZGVmIHByb2dyZXNzX2luaXQobWF4KToKICAgICAgICBnbG9iYWwgY291bnQsIHRvdGFsLCBncmFkLCBzdGVwCgogICAgICAgIHRvdGFsID0gbWF4CiAgICAgICAgY291bnQgPSAwCiAgICAgICAgc3RlcCA9IGludCh0b3RhbCAvIDEwMDApCiAgICAgICAgZ3JhZCA9IGludChzdGVwIC8gMikKCmRlZiBwcm9ncmVzcygpOgogICAgICAgIGdsb2JhbCBjb3VudCwgdG90YWwsIGdyYWQsIHN0ZXAKCiAgICAgICAgaWYgKGNvdW50ID4gZ3JhZCk6CiAgICAgICAgICAgICAgICBncmFkICs9IHN0ZXAKICAgICAgICAgICAgICAgIGcgPSBpbnQobWF0aC5mbG9vcig3Mi41KmNvdW50L3RvdGFsKzAuNSkpCiAgICAgICAgICAgICAgICBwID0gaW50KG1hdGguZmxvb3IoMTAwMC41KmNvdW50L3RvdGFsKzAuNSkpCiAgICAgICAgICAgICAgICBtc2cgPSAiSCIgKiBnICsgIi0iICogKDcyLWcpICsgIiAiICsgc3RyKHAvMTApICsgIiVcciIKICAgICAgICAgICAgICAgIGlmIChncmFkID4gdG90YWwpOgogICAgICAgICAgICAgICAgICAgICAgICBtc2cgKz0gIlxuIgoKICAgICAgICAgICAgICAgIHByaW50KG1zZywgc2VwPSIiLCBlbmQ9IiIsIGZsdXNoPVRydWUpCgojCiMgV3JpdGUgZGlnaXQgc3RyaW5nCiMKZGVmIHdyaXRlX3N0cmluZyhkaWdpdF9zdHJpbmcpOgogICAgICAgIGZkID0gb3BlbigicGktcHkudHh0IiwgbW9kZT0idyIpCgogICAgICAgIGZkLndyaXRlKCIgcGkgPSAiKQogICAgICAgIGZkLndyaXRlKGRpZ2l0X3N0cmluZ1swXSkKICAgICAgICBmZC53cml0ZSgiLiIpCgogICAgICAgIGZvciBjIGluIHJhbmdlKDEsIGxlbihkaWdpdF9zdHJpbmcpLCA1MCk6CiAgICAgICAgICAgICAgICBpZiAoYyAhPSAxKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIlx0IikKCiAgICAgICAgICAgICAgICBmZC53cml0ZShkaWdpdF9zdHJpbmdbYzpjKzUwXSkKCiAgICAgICAgICAgICAgICBpZiAoKGMgJSAxMDAwKSA9PSA5NTEpOgogICAgICAgICAgICAgICAgICAgICAgICBmZC53cml0ZSgiIDw8ICIpCiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKHN0cihjKzQ5KSkKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIlxyXG4iKQogICAgICAgICAgICAgICAgZWxpZiAoKGMgJSA1MDApID09IDQ1MSk6CiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKCIgPFxyXG4iKQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIlxyXG4iKQoKICAgICAgICAjIEZpbmFsIG5ldy1saW5lCiAgICAgICAgZmQud3JpdGUoIlxyXG4iKQoKICAgICAgICBmZC5jbG9zZSgpCgojCiMgUmVjdXJzaXZlIGZ1bmNpb24uCiMKZGVmIHMoYSwgYiwgbWF4KToKICAgICAgICBnbG9iYWwgY291bnQKCiAgICAgICAgbSA9IG1hdGguY2VpbCgoYSArIGIpIC8gMikKCiAgICAgICAgaWYgKGIgLSBhID09IDEpOgogICAgICAgICAgICAgICAgaWYgKGEgPT0gMCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAxMjAgICAgICAgICAjIDYhCiAgICAgICAgICAgICAgICAgICAgICAgIHEgPSBtcHooNjQwMzIwKiozKQogICAgICAgICAgICAgICAgICAgICAgICBwID0gZ21weTIuc3ViKCBnbXB5Mi5tdWwocSwgMTM1OTE0MDkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdtcHkyLm11bChyLCAxMzU5MTQwOSs1NDUxNDAxMzQpICkKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgIHIgPSBtcHooOCAqIChhKjYrMSkgKiAoYSo2KzMpICogKGEqNis1KSkKICAgICAgICAgICAgICAgICAgICAgICAgcSA9IG1weigoYio2NDAzMjApKiozKQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoKGIlMikgPT0gMCk6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcCA9IGdtcHkyLm11bChtcHooMTM1OTE0MDkgKyBiKjU0NTE0MDEzNCksIHIpCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcCA9IGdtcHkyLm11bChtcHooLTEzNTkxNDA5IC0gYio1NDUxNDAxMzQpLCByKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBwMSwgcTEsIHIxID0gcyhhLCBtLCBtYXgpCiAgICAgICAgICAgICAgICBwMiwgcTIsIHIyID0gcyhtLCBiLCBtYXgpCgogICAgICAgICAgICAgICAgIyBNZXJnZQogICAgICAgICAgICAgICAgcCA9IGdtcHkyLmFkZCggZ21weTIubXVsKHAxLCBxMiksIGdtcHkyLm11bChwMiwgcjEpICkKICAgICAgICAgICAgICAgIHEgPSBnbXB5Mi5tdWwocTEsIHEyKQoKICAgICAgICAgICAgICAgIGlmIChiICE9IG1heCk6CiAgICAgICAgICAgICAgICAgICAgICAgIHIgPSBnbXB5Mi5tdWwocjEsIHIyKQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgciA9IDAKCiAgICAgICAgY291bnQgKz0gMQogICAgICAgIHByb2dyZXNzKCkKCiAgICAgICAgcmV0dXJuIHAsIHEsIHIKCiMKIyBDYWxjdWxhdGUgZQojCmRlZiBjYWxjX3BpKGRpZ2l0cyk6CiAgICAgICAgZ2xvYmFsIHRvdGFsCgogICAgICAgIGQgPSBkaWdpdHMrMQogICAgICAgIG5fdGVybXMgPSBtYXRoLmNlaWwoZCptYXRoLmxvZygxMCkvKDMqbWF0aC5sb2coNTMzNjApKSkKICAgICAgICBwcmVjaXNpb24gPSBtYXRoLmNlaWwoZCAqIG1hdGgubG9nMigxMCkpICsgNAogICAgICAgIHByaW50KCJkID0gIiwgZCwgIiwgbiA9ICIsIG5fdGVybXMsICIsIHByZWNpc2lvbiA9ICIsIHByZWNpc2lvbiwgc2VwPSIiKQoKICAgICAgICBwcmludCgiZ21weTIgdmVyc2lvbjoiLCBnbXB5Mi52ZXJzaW9uKCkpCiAgICAgICAgcHJpbnQoIk1QIHZlcnNpb246IiwgZ21weTIubXBfdmVyc2lvbigpKQogICAgICAgIHByaW50KCJNUEZSIHZlcnNpb246IiwgZ21weTIubXBmcl92ZXJzaW9uKCkpCgogICAgICAgIG1heF9wcmVjaXNpb24gPSBnbXB5Mi5nZXRfbWF4X3ByZWNpc2lvbigpCiAgICAgICAgcHJpbnQoIm1heF9wcmVjaXNpb24gPSIsIG1heF9wcmVjaXNpb24pCiAgICAgICAgbWF4X2VtYXggPSBnbXB5Mi5nZXRfZW1heF9tYXgoKQogICAgICAgIHByaW50KCJtYXhfZW1heCA9IiwgbWF4X2VtYXgpCgogICAgICAgIGlmIChtYXhfcHJlY2lzaW9uIDwgcHJlY2lzaW9uKToKICAgICAgICAgICAgICAgIHByaW50KCJFcnJvciEgTWF4IHByZWNpc2lvbiBpcyB0b28gc21hbGwhIFByb2dyYW0gdGVybWluYXRlZC4iKQogICAgICAgICAgICAgICAgcmV0dXJuCgogICAgICAgIGdtcHkyLmdldF9jb250ZXh0KCkucHJlY2lzaW9uID0gcHJlY2lzaW9uCiAgICAgICAgZ21weTIuZ2V0X2NvbnRleHQoKS5lbWF4ID0gbWF4X2VtYXgKICAgICAgICBwcmludCgiUmVhbCBwcmVjaXNpb24gPSAiLCBnbXB5Mi5nZXRfY29udGV4dCgpLnByZWNpc2lvbikKICAgICAgICBwcm9ncmVzc19pbml0KG5fdGVybXMgKiAyIC0gMSkgICAgICAgICAgICAgICAgICAgICAgICAgICMgSW5pdGlhbGl6ZSBwcm9ncmVzcyBiYXIKCiAgICAgICAgIyBSZWN1cnNpb24KICAgICAgICBzdGFydF90aW1lID0gdGltZS5tb25vdG9uaWNfbnMoKQogICAgICAgIHAsIHEsIHIgPSBzKDAsIG5fdGVybXMsIG5fdGVybXMpCiAgICAgICAgZW5kX3RpbWUgPSB0aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgZWxhcHNlZCA9IChlbmRfdGltZSAtIHN0YXJ0X3RpbWUpIC8gMTAwMDAwMDAwMAogICAgICAgIHByaW50KCJSZWN1cnNpb246IiwgZWxhcHNlZCwgInNlY29uZHMuIikKCiAgICAgICAgc3RhcnRfdGltZSA9IHRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICBxID0gZ21weTIubXVsKHEsIDQyNjg4MCkKICAgICAgICBlbmRfdGltZSA9IHRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICBlbGFwc2VkID0gKGVuZF90aW1lIC0gc3RhcnRfdGltZSkgLyAxMDAwMDAwMDAwCiAgICAgICAgcHJpbnQoIk11bHRpcGx5IGJ5IDQyNjg4MDoiLCBlbGFwc2VkLCAic2Vjb25kcy4iKQoKICAgICAgICBzdGFydF90aW1lID0gdGltZS5tb25vdG9uaWNfbnMoKQogICAgICAgIHBmID0gbXBmcihwKQogICAgICAgIHFmID0gbXBmcihxKQogICAgICAgIGVmID0gZ21weTIuZGl2KHFmLCBwZikKICAgICAgICBlbmRfdGltZSA9IHRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICBlbGFwc2VkID0gKGVuZF90aW1lIC0gc3RhcnRfdGltZSkgLyAxMDAwMDAwMDAwCiAgICAgICAgcHJpbnQoIkdyYW5kIERpdmlzaW9uOiIsIGVsYXBzZWQsICJzZWNvbmRzLiIpCgogICAgICAgIHN0YXJ0X3RpbWUgPSB0aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgZWYgPSBnbXB5Mi5tdWwoZWYsIGdtcHkyLnNxcnQoMTAwMDUpKQogICAgICAgIGVuZF90aW1lID0gdGltZS5tb25vdG9uaWNfbnMoKQogICAgICAgIGVsYXBzZWQgPSAoZW5kX3RpbWUgLSBzdGFydF90aW1lKSAvIDEwMDAwMDAwMDAKICAgICAgICBwcmludCgiTXVsdGlwbHkgYnkgc3FydCgxMDAwNSk6IiwgZWxhcHNlZCwgInNlY29uZHMuIikKCiAgICAgICAgIyBDb252ZXJ0IHRvIGRlY2ltYWwgZGlnaXRzCiAgICAgICAgc3RhcnRfdGltZSA9IHRpbWUubW9ub3RvbmljX25zKCkKICAgICAgICBlc3RyLCBleHAsIHByZWMgPSBtcGZyLmRpZ2l0cyhlZikKICAgICAgICBlc3RyID0gZXN0clswOmRdCiAgICAgICAgZW5kX3RpbWUgPSB0aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgZWxhcHNlZCA9IChlbmRfdGltZSAtIHN0YXJ0X3RpbWUpIC8gMTAwMDAwMDAwMAogICAgICAgIHByaW50KCJDb252ZXJ0IHRvIGRlY2ltYWwgZGlnaXRzOiIsIGVsYXBzZWQsICJzZWNvbmRzLiIpCgogICAgICAgICMgV3JpdGUgdG8gZmlsZQogICAgICAgIHN0YXJ0X3RpbWUgPSB0aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgd3JpdGVfc3RyaW5nKGVzdHIpCiAgICAgICAgZW5kX3RpbWUgPSB0aW1lLm1vbm90b25pY19ucygpCiAgICAgICAgZWxhcHNlZCA9IChlbmRfdGltZSAtIHN0YXJ0X3RpbWUpIC8gMTAwMDAwMDAwMAogICAgICAgIHByaW50KCJXcml0ZSB0byBmaWxlOiIsIGVsYXBzZWQsICJzZWNvbmRzLiIpCgojCiMgIG1haW4gcHJvZ3JhbQojCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICAgICAgYXJnYyA9IGxlbihzeXMuYXJndikKICAgICAgICBpZiAoYXJnYyA+PSAyKToKICAgICAgICAgICAgICAgIGRpZ2l0cyA9IGludChzeXMuYXJndlsxXSkKICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgZGlnaXRzID0gMTAwMDAwCgogICAgICAgIGNhbGNfcGkoZGlnaXRzKQoKIyBFbmQgb2YgcGkucHkK