Search code examples
pythonmpmath

Python: mpmath lose precision when divide large number


I came across a π algorithm called Chudnovsky algorithm. A Python implementation is showed on Wikipedia which use decimal package comes with Python. But recently when I test Gauss Legendre algorithm I found mpmath package runs much more efficient than decimal when deals with high precision calculation, so I hope the algorithm could work with mpmath. Here is my code:

#!/usr/bin/env python

from mpmath import *
import pi_compare # A module aim to compare result with standard pi

mp.dps = 1000
def pi():
    K, M, L, X, S = 6, mpf('1'), 13591409, 1, mpf('13591409')
    for i in xrange(0,100):
        M = (K**3 - K*16) * M / K**3
        L += 545140134
        X *= -262537412640768000
        S += (M * L) / X
        K += 12
    return mpf('426880') * mpf('10005').sqrt() / S

P = pi()
print P
print pi_compare.compare(str(P))

I do believe Python itself could deal with large integer so I do not use mpmath on var K, L, X as in iteration no decimal part will turn up. I think the matter occur on S += (M * L) / X as X is a quite large number. It confused me a lot to deal with such a large number, hope for your advice, thanks.


Solution

  • As well as the typo mentioned by DSM, there's another problem with that code. The division by k**3 needs to be floor division, not float division. Here are repaired versions using both the decimal and the mpmath modules. This code works on both Python 2 & Python 3.

    from decimal import Decimal as Dec, getcontext as gc
    from mpmath import mp
    
    def pi_dec(maxK=70, prec=1008):
        gc().prec = prec
        K, M, L, X, S = 6, 1, 13591409, 1, 13591409 
        for k in range(1, maxK+1):
            M = (K**3 - (K<<4)) * M // k**3 
            L += 545140134
            X *= -262537412640768000
            S += Dec(M * L) / X
            K += 12
        pi = 426880 * Dec(10005).sqrt() / S
        return pi
    
    def pi_mp(maxK=70, prec=1008):
        mp.dps = prec
        K, M, L, X, S = 6, 1, 13591409, 1, 13591409 
        for k in range(1, maxK+1):
            M = (K**3 - (K<<4)) * M // k**3 
            L += 545140134
            X *= -262537412640768000
            S += mp.mpf(M * L) / X
            K += 12
        pi = 426880 * mp.sqrt(10005) / S
        return pi
    
    
    Pi = pi_dec()
    print(Pi)
    
    Pi = pi_mp()
    print(Pi)
    

    output

    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809533 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809523

    For comparison purposes, here's the value of mp.pi:

    mp.dps = 1008
    print(mp.pi)
    

    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525