Chudnovsky algorithm

From testwiki
Revision as of 17:44, 30 January 2025 by imported>MichaelMaggs (Undid revision 1272879279 by 86.27.51.52 (talk) Not helpful)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Template:Short description The Chudnovsky algorithm is a fast method for calculating the digits of [[pi|Template:Pi]], based on Ramanujan's [[List of formulae involving π#Efficient infinite series|Template:Pi formulae]]. Published by the Chudnovsky brothers in 1988,[1] it was used to calculate Template:Pi to a billion decimal places.[2]

It was used in the world record calculations of 2.7 trillion digits of Template:Pi in December 2009,[3] 10 trillion digits in October 2011,[4][5] 22.4 trillion digits in November 2016,[6] 31.4 trillion digits in September 2018–January 2019,[7] 50 trillion digits on January 29, 2020,[8] 62.8 trillion digits on August 14, 2021,[9] 100 trillion digits on March 21, 2022,[10] 105 trillion digits on March 14, 2024,[11] and 202 trillion digits on June 28, 2024.[12]

Algorithm

The algorithm is based on the negated Heegner number d=164, the j-function j(1+i1632)=6403203, and on the following rapidly convergent generalized hypergeometric series:[13]1π=12k=0(1)k(6k)!(545140134k+13591409)(3k)!(k!)3(640320)3k+3/2A detailed proof of this formula can be found here: [14]


This identity is similar to some of Ramanujan's formulas involving Template:Pi,[13] and is an example of a Ramanujan–Sato series.

The time complexity of the algorithm is O(n(logn)3).[15]

Optimizations

The optimization technique used for the world record computations is called binary splitting.[16]

Binary splitting

A factor of 1/6403203/2 can be taken out of the sum and simplified to1π=142688010005k=0(1)k(6k)!(545140134k+13591409)(3k)!(k!)3(640320)3k


Let f(n)=(1)n(6n)!(3n)!(n!)3(640320)3n, and substitute that into the sum.1π=142688010005k=0f(k)(545140134k+13591409)


f(n)f(n1) can be simplified to (6n1)(2n1)(6n5)10939058860032000n3, sof(n)=f(n1)(6n1)(2n1)(6n5)10939058860032000n3

f(0)=1 from the original definition of f, sof(n)=j=1n(6j1)(2j1)(6j5)10939058860032000j3

This definition of f is not defined for n=0, so compute the first term of the sum and use the new definition of f1π=142688010005(13591409+k=1(j=1k(6j1)(2j1)(6j5)10939058860032000j3)(545140134k+13591409))

Let P(a,b)=j=ab1(6j1)(2j1)(6j5) and Q(a,b)=j=ab110939058860032000j3, so1π=142688010005(13591409+k=1P(1,k+1)Q(1,k+1)(545140134k+13591409))

Let S(a,b)=k=ab1P(a,k+1)Q(a,k+1)(545140134k+13591409) and R(a,b)=Q(a,b)S(a,b)π=4268801000513591409+S(1,)

S(1,) can never be computed, so instead compute S(1,n) and as n approaches , the π approximation will get better.π=limn4268801000513591409+S(1,n)

From the original definition of R, S(a,b)=R(a,b)Q(a,b)π=limn42688010005Q(1,n)13591409Q(1,n)+R(1,n)

Recursively computing the functions

Consider a value m such that a<m<b

  • P(a,b)=P(a,m)P(m,b)
  • Q(a,b)=Q(a,m)Q(m,b)
  • S(a,b)=S(a,m)+P(a,m)Q(a,m)S(m,b)
  • R(a,b)=Q(m,b)R(a,m)+P(a,m)R(m,b)

Base case for recursion

Consider b=a+1

  • P(a,a+1)=(6a1)(2a1)(6a5)
  • Q(a,a+1)=10939058860032000a3
  • S(a,a+1)=P(a,a+1)Q(a,a+1)(545140134a+13591409)
  • R(a,a+1)=P(a,a+1)(545140134a+13591409)

Python code

#Note: For extreme calculations, other code can be used to run on a GPU, which is much faster than this.
import decimal


def binary_split(a, b):
    if b == a + 1:
        Pab = -(6*a - 5)*(2*a - 1)*(6*a - 1)
        Qab = 10939058860032000 * a**3
        Rab = Pab * (545140134*a + 13591409)
    else:
        m = (a + b) // 2
        Pam, Qam, Ram = binary_split(a, m)
        Pmb, Qmb, Rmb = binary_split(m, b)
        
        Pab = Pam * Pmb
        Qab = Qam * Qmb
        Rab = Qmb * Ram + Pam * Rmb
    return Pab, Qab, Rab


def chudnovsky(n):
    """Chudnovsky algorithm."""
    P1n, Q1n, R1n = binary_split(1, n)
    return (426880 * decimal.Decimal(10005).sqrt() * Q1n) / (13591409*Q1n + R1n)


print(f"1 = {chudnovsky(2)}")  # 3.141592653589793238462643384

decimal.getcontext().prec = 100 # number of digits of decimal precision
for n in range(2,10):
    print(f"{n} = {chudnovsky(n)}")  # 3.14159265358979323846264338...

Notes

eπ1636403203+743.99999999999925
6403203/24=10939058860032000
545140134=16312719117322
13591409=131045493

See also

Template:Portal

  • [1] How is π calculated to trillions of digits?

References

Template:Reflist