#
# e.py - Calculate Eular's number e
#
import sys
import math
import gmpy2
from gmpy2 import mpfr
from gmpy2 import mpz
#
# Constants used in Stirling's approximation
#
E = float(2.718281828459045235360287)
pi = float(3.141592653589793238462643)
C = math.log10(2*pi) / 2
#
# Global Variables
#
count = 0
total = 0
old_p = 0
#
# Stirling's approximation
#
def logfactorial(n):
return (C + math.log10(n)/2 + n*(math.log10(n)-math.log10(E))) ;
#
# Estimate how many terms in the serie sould be calculated.
#
def terms(digits):
upper = 2;
lower = 1;
while (logfactorial(upper)<digits):
upper <<= 1
else:
lower = upper/2;
while ((upper-lower) > 1):
n = (upper+lower)/2
if (logfactorial(n) > digits):
upper = n;
else:
lower = n;
return n
#
# 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("e-py.txt", mode="w")
fd.write(" e = ")
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):
global count
m = math.ceil((a + b) / 2)
if (a == b):
q = mpz(1)
if (a == 0):
p = mpz(1)
else:
p = mpz(0)
elif (b - a == 1):
if (a == 0):
p = mpz(2)
q = mpz(1)
else:
p = mpz(1)
q = mpz(b)
else:
p1, q1 = s(a, m)
p2, q2 = s(m, b)
# Merge
p = gmpy2.add(gmpy2.mul(p1, q2), p2)
q = gmpy2.mul(q1, q2)
count += 1
progress()
return p, q;
#
# Calculate e
#
def calc_e(digits):
global total
d = digits+1
n_terms = int(terms(d))
precision = math.ceil(d * math.log2(10)) + 4;
print("d = ", d, ", n = ", n_terms, ", precision = ", precision)
print("gmpy2 version:", gmpy2.version())
print("MP version:", gmpy2.mp_version())
print("MPFR version:", gmpy2.mpfr_version())
max_precision = gmpy2.get_max_precision()
if (max_precision < precision):
print("Error! max precision", max_precision,
"is smaller than required precision", precision)
return
gmpy2.get_context().precision = precision
print("Real precision = ", gmpy2.get_context().precision)
emax = gmpy2.get_emax_max()
print("gmpy2 emax max =", emax)
gmpy2.get_context().emax = emax;
total = n_terms * 2 - 1 # Max progress
p, q = s(0, n_terms)
pf = mpfr(p);
qf = mpfr(q);
ef = gmpy2.div(p, q)
estr, exp, prec = mpfr.digits(ef)
estr = estr[0:d]
write_string(estr);
#
# main program
#
argc = len(sys.argv)
if (argc >= 2):
digits = int(sys.argv[1])
else:
digits = 100000
calc_e(digits)
# End of e.py
IwojICBlLnB5IC0gQ2FsY3VsYXRlIEV1bGFyJ3MgbnVtYmVyIGUKIwppbXBvcnQgc3lzCmltcG9ydCBtYXRoCmltcG9ydCBnbXB5Mgpmcm9tIGdtcHkyIGltcG9ydCBtcGZyCmZyb20gZ21weTIgaW1wb3J0IG1wegoKIwojIENvbnN0YW50cyB1c2VkIGluIFN0aXJsaW5nJ3MgYXBwcm94aW1hdGlvbgojCkUgICAgICAgPSBmbG9hdCgyLjcxODI4MTgyODQ1OTA0NTIzNTM2MDI4NykKcGkgICAgICA9IGZsb2F0KDMuMTQxNTkyNjUzNTg5NzkzMjM4NDYyNjQzKQpDICAgICAgID0gbWF0aC5sb2cxMCgyKnBpKSAvIDIKCiMKIyBHbG9iYWwgVmFyaWFibGVzCiMKY291bnQgPSAwCnRvdGFsID0gMApvbGRfcCA9IDAKCiMKIyBTdGlybGluZydzIGFwcHJveGltYXRpb24KIwpkZWYgbG9nZmFjdG9yaWFsKG4pOgogICAgICAgIHJldHVybiAoQyArIG1hdGgubG9nMTAobikvMiArIG4qKG1hdGgubG9nMTAobiktbWF0aC5sb2cxMChFKSkpIDsKCiMKIyBFc3RpbWF0ZSBob3cgbWFueSB0ZXJtcyBpbiB0aGUgc2VyaWUgc291bGQgYmUgY2FsY3VsYXRlZC4KIwpkZWYgdGVybXMoZGlnaXRzKToKICAgICAgICB1cHBlciA9IDI7CiAgICAgICAgbG93ZXIgPSAxOwogICAgICAgIHdoaWxlIChsb2dmYWN0b3JpYWwodXBwZXIpPGRpZ2l0cyk6CiAgICAgICAgICAgICAgICB1cHBlciA8PD0gMQogICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBsb3dlciA9IHVwcGVyLzI7CgogICAgICAgIHdoaWxlICgodXBwZXItbG93ZXIpID4gMSk6CiAgICAgICAgICAgICAgICBuID0gKHVwcGVyK2xvd2VyKS8yCiAgICAgICAgICAgICAgICBpZiAobG9nZmFjdG9yaWFsKG4pID4gZGlnaXRzKToKICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBuOwogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBuOwoKICAgICAgICByZXR1cm4gbgoKIwojIFNob3cgUHJvZ3Jlc3MKIwpkZWYgcHJvZ3Jlc3MoKToKICAgICAgICBnbG9iYWwgY291bnQsIG9sZF9wLCB0b3RhbAoKICAgICAgICBwID0gaW50KG1hdGguZmxvb3IoMTAwMCpjb3VudC90b3RhbCswLjUpKQogICAgICAgIGlmIChwID4gb2xkX3ApOgogICAgICAgICAgICAgICAgb2xkX3AgPSBwCiAgICAgICAgICAgICAgICBnID0gaW50KG1hdGguZmxvb3IoNzIuNSpjb3VudC90b3RhbCswLjUpKQogICAgICAgICAgICAgICAgZm9yIGMgaW4gcmFuZ2UoNzIpOgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoYzxnKToKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludCgiSCIsIHNlcD0iIiwgZW5kPSIiKQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50KCItIiwgc2VwPSIiLCBlbmQ9IiIpCiAgICAgICAgICAgICAgICBwcmludCgiICIsIHAvMTAsICIlXHIiLCBzZXA9IiIsIGVuZD0iIiwgZmx1c2g9VHJ1ZSkKCiAgICAgICAgaWYgKGNvdW50ID09IHRvdGFsKToKICAgICAgICAgICAgICAgIHByaW50KCJcbiIsIHNlcD0iIiwgZW5kPSIiKQoKIwojIFdyaXRlIGRpZ2l0IHN0cmluZwojCmRlZiB3cml0ZV9zdHJpbmcoZGlnaXRfc3RyaW5nKToKICAgICAgICBmZCA9IG9wZW4oImUtcHkudHh0IiwgbW9kZT0idyIpCgogICAgICAgIGZkLndyaXRlKCIgIGUgPSAiKQogICAgICAgIGZvciBjIGluIHJhbmdlKGxlbihkaWdpdF9zdHJpbmcpKToKICAgICAgICAgICAgICAgIGlmICgoYyAhPSAxKSBhbmQgKGMgJSA1MCA9PSAxKSk6CiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcdCIpCiAgICAgICAgICAgICAgICBmZC53cml0ZShkaWdpdF9zdHJpbmdbY10pCiAgICAgICAgICAgICAgICBpZiAoYyA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIi4iKQogICAgICAgICAgICAgICAgZWxpZiAoKGMgJSAxMDAwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiA8PCAiKQogICAgICAgICAgICAgICAgICAgICAgICBmZC53cml0ZShzdHIoYykpCiAgICAgICAgICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcclxuIikKICAgICAgICAgICAgICAgIGVsaWYgKChjICUgNTAwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiA8XHJcbiIpCiAgICAgICAgICAgICAgICBlbGlmICgoYyAlIDUwKSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIlxyXG4iKQogICAgICAgICAgICAgICAgZWxpZiAoKGMgJSA1KSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgZmQud3JpdGUoIiAiKQoKICAgICAgICAjIEZpbmFsIG5ldy1saW5lCiAgICAgICAgaWYgKChjJTUwKSAhPSAwKToKICAgICAgICAgICAgICAgIGZkLndyaXRlKCJcclxuIikKCiAgICAgICAgZmQuY2xvc2UoKQoKIwojIFJlY3Vyc2l2ZSBmdW5jaW9uLgojCmRlZiBzKGEsIGIpOgogICAgICAgIGdsb2JhbCBjb3VudAoKICAgICAgICBtID0gbWF0aC5jZWlsKChhICsgYikgLyAyKQoKICAgICAgICBpZiAoYSA9PSBiKToKICAgICAgICAgICAgICAgIHEgPSBtcHooMSkKICAgICAgICAgICAgICAgIGlmIChhID09IDApOgogICAgICAgICAgICAgICAgICAgICAgICBwID0gbXB6KDEpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBwID0gbXB6KDApCiAgICAgICAgZWxpZiAoYiAtIGEgPT0gMSk6CiAgICAgICAgICAgICAgICBpZiAoYSA9PSAwKToKICAgICAgICAgICAgICAgICAgICAgICAgcCA9IG1weigyKQogICAgICAgICAgICAgICAgICAgICAgICBxID0gbXB6KDEpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICBwID0gbXB6KDEpCiAgICAgICAgICAgICAgICAgICAgICAgIHEgPSBtcHooYikKICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcDEsIHExID0gcyhhLCBtKQogICAgICAgICAgICAgICAgcDIsIHEyID0gcyhtLCBiKQoKICAgICAgICAgICAgICAgICMgTWVyZ2UKICAgICAgICAgICAgICAgIHAgPSBnbXB5Mi5hZGQoZ21weTIubXVsKHAxLCBxMiksIHAyKQogICAgICAgICAgICAgICAgcSA9IGdtcHkyLm11bChxMSwgcTIpCgogICAgICAgIGNvdW50ICs9IDEKICAgICAgICBwcm9ncmVzcygpCgogICAgICAgIHJldHVybiBwLCBxOwoKIwojIENhbGN1bGF0ZSBlCiMKZGVmIGNhbGNfZShkaWdpdHMpOgogICAgICAgIGdsb2JhbCB0b3RhbAoKICAgICAgICBkID0gZGlnaXRzKzEKICAgICAgICBuX3Rlcm1zID0gaW50KHRlcm1zKGQpKQogICAgICAgIHByZWNpc2lvbiA9IG1hdGguY2VpbChkICogbWF0aC5sb2cyKDEwKSkgKyA0OwogICAgICAgIHByaW50KCJkID0gIiwgZCwgIiwgbiA9ICIsIG5fdGVybXMsICIsIHByZWNpc2lvbiA9ICIsIHByZWNpc2lvbikKCiAgICAgICAgcHJpbnQoImdtcHkyIHZlcnNpb246IiwgZ21weTIudmVyc2lvbigpKQogICAgICAgIHByaW50KCJNUCB2ZXJzaW9uOiIsIGdtcHkyLm1wX3ZlcnNpb24oKSkKICAgICAgICBwcmludCgiTVBGUiB2ZXJzaW9uOiIsIGdtcHkyLm1wZnJfdmVyc2lvbigpKQogICAgICAgIG1heF9wcmVjaXNpb24gPSBnbXB5Mi5nZXRfbWF4X3ByZWNpc2lvbigpCiAgICAgICAgaWYgKG1heF9wcmVjaXNpb24gPCBwcmVjaXNpb24pOgogICAgICAgICAgICAgICAgcHJpbnQoIkVycm9yISBtYXggcHJlY2lzaW9uIiwgbWF4X3ByZWNpc2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgImlzIHNtYWxsZXIgdGhhbiByZXF1aXJlZCBwcmVjaXNpb24iLCBwcmVjaXNpb24pCiAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICBnbXB5Mi5nZXRfY29udGV4dCgpLnByZWNpc2lvbiA9IHByZWNpc2lvbgogICAgICAgIHByaW50KCJSZWFsIHByZWNpc2lvbiA9ICIsIGdtcHkyLmdldF9jb250ZXh0KCkucHJlY2lzaW9uKQoKICAgICAgICBlbWF4ID0gZ21weTIuZ2V0X2VtYXhfbWF4KCkKICAgICAgICBwcmludCgiZ21weTIgZW1heCBtYXggPSIsIGVtYXgpCiAgICAgICAgZ21weTIuZ2V0X2NvbnRleHQoKS5lbWF4ID0gZW1heDsKCiAgICAgICAgdG90YWwgPSBuX3Rlcm1zICogMiAtIDEgICAgICAgICAjIE1heCBwcm9ncmVzcwoKICAgICAgICBwLCBxID0gcygwLCBuX3Rlcm1zKQoKICAgICAgICBwZiA9IG1wZnIocCk7CiAgICAgICAgcWYgPSBtcGZyKHEpOwogICAgICAgIGVmID0gZ21weTIuZGl2KHAsIHEpCiAgICAgICAgZXN0ciwgZXhwLCBwcmVjID0gbXBmci5kaWdpdHMoZWYpCiAgICAgICAgZXN0ciA9IGVzdHJbMDpkXQogICAgICAgIHdyaXRlX3N0cmluZyhlc3RyKTsKCiMKIyAgbWFpbiBwcm9ncmFtCiMKYXJnYyA9IGxlbihzeXMuYXJndikKaWYgKGFyZ2MgPj0gMik6CiAgICAgICAgZGlnaXRzID0gaW50KHN5cy5hcmd2WzFdKQplbHNlOgogICAgICAgIGRpZ2l0cyA9IDEwMDAwMAoKY2FsY19lKGRpZ2l0cykKCiMgRW5kIG9mIGUucHkK