#
#  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
