Compute Pi in Python


# This program computes Pi by the formula:
# pi / 4 = 4 * ArcTan(1/5) - ArcTan(1/239)

# Adapted from some program I found on the Internet a long time
# ago that computed Pi by:
# pi / 4 = ArcTan(1/2) + ArcTan(1/3)

# I have no idea who wrote the original program nor remember where
# I found it--there wasn't any credits in the original C source.  This
# one also no longer looks like the original as I've completely rewritten
# it.  I got a lot of my information from
# http://www.boo.net/~jasonp/pipage.html when I rewrote the program.  This
# program will reliably compute upto 1,000,000 digits, that I've verified.

# There are faster ways of computing Pi, and this program probably
# could be optimized further, but it is sufficiently fast for computing
# Pi using relatively portable and understandable routines that can
# be easily converted into other languages.

# Computing Pi using FFTs are much much faster, but also much more
# complicated.  Using the ArcTan methods are fairly simple to implement,
# but not nearly as fast as the FFT methods.  Also, the
# pi / 4 = 4 * ArcTan(1/5) - ArcTan(1/239) formula is one of the faster
# of the various ArcTan formulas for computing PI.

# Author: M. Scott Reynolds
# Date: 16 March 2022

import sys

# Compute pi up to max_ditgits long.
# Return result as a string.
def pi(max_ditgits):
    SIZE = 1000

    # Initialize
    precision = (max_ditgits-1) // 3 + 3
    p = [0 for i in range(precision+1)]
    t = [0 for i in range(precision+1)]

    # Note, borrows and carries from the addition and subtraction
    # are postponed till last.  

    # Compute arctan(1/5)

    # t = t / 5, p = t
    t[0] = 1
    remainder1 = 0
    i = 0
    while i <= precision:
        b = SIZE * remainder1 + t[i]
        t[i] = b // 5
        p[i] = t[i]
        remainder1 = b % 5
        i += 1

    # While t is not zero.
    n = -1
    n2 = 1
    is_zero = False
    while not is_zero:
        remainder1 = 0
        remainder2 = 0
        remainder3 = 0
        remainder4 = 0
        is_zero = True
        n += 4
        n2 += 4
        i = 0
        while i <= precision:
            b = SIZE * remainder1 + t[i]
            t[i] = b // 25
            remainder1 = b % 25

            b = SIZE * remainder2 + t[i]
            p[i] -= b // n
            remainder2 = b % n

            b = SIZE * remainder3 + t[i]
            t[i] = b // 25
            remainder3 = b % 25

            b = SIZE * remainder4 + t[i]
            p[i] += b // n2
            remainder4 = b % n2

            if is_zero and t[i] != 0:
                is_zero = False
            i += 1

    # p = p * 4
    carry = 0
    i = precision
    while i >= 0:
        b = p[i] * 4 + carry
        p[i] = b % SIZE
        carry = b // SIZE
        i -= 1

    # Compute arctan(1/239)

    # t = t / 239, p = p - t
    t[0] = 1
    remainder1 = 0
    i = 0
    while i <= precision:
        b = SIZE * remainder1 + t[i]
        t[i] = b // 239
        p[i] -= t[i]
        remainder1 = b % 239
        i += 1

    # While t is not zero.
    n = -1
    n2 = 1
    is_zero = False
    while not is_zero:
        # t = t / 57121, p = p + t / n, t = t / 57121, p = p - t / (n+2)
        remainder1 = 0
        remainder2 = 0
        remainder3 = 0
        remainder4 = 0
        is_zero = True
        n += 4
        n2 += 4
        i = 0
        while i <= precision:
            b = SIZE * remainder1 + t[i]
            t[i] = b // 57121
            remainder1 = b % 57121

            b = SIZE * remainder2 + t[i]
            p[i] += b // n
            remainder2 = b % n

            b = SIZE * remainder3 + t[i]
            t[i] = b // 57121
            remainder3 = b % 57121

            b = SIZE * remainder4 + t[i]
            p[i] -= b // n2
            remainder4 = b % n2

            if is_zero and t[i] != 0:
                is_zero = False
            i += 1

    # p = p * 4
    carry = 0
    i = precision
    while i >= 0:
        b = p[i] * 4 + carry
        p[i] = b % SIZE
        carry = b // SIZE
        i -= 1

    # Borrow and carry.
    i = precision
    while i >= 1:
        if p[i] < 0:
            b = p[i] // SIZE
            p[i] -= (b - 1) * SIZE
            p[i-1] += b - 1

        if p[i] >= SIZE:
            b = p[i] // SIZE
            p[i] -= b * SIZE
            p[i-1] += b
        i -= 1

    # Store results as a string.
    text = str(p[0]) + "."
    i = 1
    while i < precision:
        if p[i] < 10:
            text += "00"
        elif p[i] < 100:
            text += "0"
        text += str(p[i])
        i += 1

    return text

# Get total digits from command line, or default to 1000
total_digits = 1000
if len(sys.argv) > 1:
    total_digits = int(sys.argv[1])

text = pi(total_digits)

# Print formatted results.
print("3.")
for i in range(1, total_digits+1):
    print(text[i+1], end='')
    if i % 1000 == 0:
        print()
        print()
    elif i % 50 == 0:
        print()
    elif i % 10 == 0:
        print(" ", end='')


Leave a comment