Search code examples
pythonpython-3.xmathdecimalfloating-accuracy

python math.log inaccurate output at larger int?


This is my code and i am trying to use math.log to find log of an int. i tried most of the way to solve inaccurate log but nothing seems to work my piece of code :

num = 810333333333333333253432343224234
print(num)
getcontext().prec = 100 # set the precision  (no. of digits)
getcontext().rounding = ROUND_DOWN  # this will effectively truncate
logA = Decimal(math.log(num,2))

print(logA)
#find num using component of logs
seedfrac = Decimal(logA - int(logA))
nonfrac = 2**int(logA)
frac = Decimal(2**seedfrac)
print(Decimal(frac*nonfrac))
#find num directly 
print(Decimal(2**logA ))

Output to check values:

810333333333333333253432343224234
109.320214523928456173962331376969814300537109375
810333333333340688230991571062453.5576735355138989553226940926052307835750320132600744995177525695124
810333333333340688230991571062453.5576735355138989553226940926052307835750320132600744995177525695128

Please reply if you know any workaround,Thanks.


Solution

  • math.log only works on floats, so when you do Decimal(math.log(num,2)) you're just calling Decimal on the result of converting num to a float and then taking its float-precision log.

    Convert your number to a Decimal instance first, preserving the precision, and then use one of its logarithm methods (newlines inserted below for readability):

    In [22]: Decimal(num)
    Out[22]: Decimal('810333333333333333253432343224234')
    
    In [23]: Decimal(num).ln()
    Out[23]: Decimal('75.77499847546938418941086142055648421904630259496362044
                      157156139031463040418047508186428539214239394')
    
    In [24]: Decimal(num).ln().exp()
    Out[24]: Decimal('810333333333333333253432343224234.0000000000000000000000
                      000000000000000000000000000000000000000000020')
    
    In [25]: Decimal(num).ln() / Decimal(2).ln()
    Out[25]: Decimal('109.32021452392844307936383214097698765413874994582696830
                      23528366628242511675596034347551786781907708')
    
    In [26]: 2**(Decimal(num).ln() / Decimal(2).ln())
    Out[26]: Decimal('810333333333333333253432343224233.999999999999999999999
                      9999999999999999999999999999999999999999999548')