Romen
Romen

Reputation: 1

Why does python limit the number of decimals?

pi=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
U = 314
D = 100
print(U/D,U,D)

best=3.0
while True:
    if abs((U+1)/D-pi)<abs(U/D-pi):
        if abs((U+1)/D-pi)<abs(best-pi):
            best=(U+1)/D
            print(U+1,D,abs((U+1)/D-pi))
        U+=1

        
    elif abs((U-1)/D-pi)<abs(U/D-pi):
        if abs((U-1)/D-pi)<abs(best-pi):
            best=(U-1)/D
            print(U,D,abs((U-1)/D-pi))
        U-=1

    else:
        D+=1

Im running this code to try to find factors estimates of pi, but as you can see below eventually the decimals don't go any further and the program tells me the error between pi and my number is 0 which cant be true as pi isn't a factor.

How can I change the code so the decimal limit is higher than e-17?

I already tried multiplying every value by 1e17 but then it still prints 0 for the final factors.

image of factor prints

Upvotes: -3

Views: 110

Answers (4)

Mark Tolonen
Mark Tolonen

Reputation: 178021

A Python float typically has 53 binary digits of precision. That translates to about 16 decimal digits of precision. Use the decimal module for high precision decimals:

import decimal as d

d.getcontext().prec = 30  # decimal digits of precision.

pi = d.Decimal('3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679')
U = d.Decimal('314')
D = d.Decimal('100')
print(U / D, U, D)

best=d.Decimal('3.0')
while True:
    if abs((U + 1) / D - pi) < abs(U / D - pi):
        if abs((U + 1) / D - pi) < abs(best - pi):
            best=(U + 1) / D
            print(U + 1, D, abs((U + 1) / D - pi))
        U += 1
    elif abs((U - 1) / D - pi) < abs(U / D - pi):
        if abs((U - 1) / D - pi) < abs(best - pi):
            best=(U - 1) / D
            print(U, D, abs((U - 1) / D - pi))
        U -= 1
    else:
        D += 1

Output:

...
4272943 1360120 4.04066918956061569502884197169E-13
5419351 1725033 2.21447793003940304971158028306E-14
42208400 13435351 2.10025158489898895028841971694E-14
47627751 15160384 1.60929760910637595028841971694E-14
53047102 16885417 1.21865644284916995028841971694E-14
58466453 18610450 9.00433611769475950288419716940E-15
63885804 20335483 6.36199651764630950288419716940E-15
69305155 22060516 4.13289503109351950288419716940E-15
74724506 23785549 2.22712210211597950288419716940E-15
80143857 25510582 5.79087016437569502884197169399E-16
165707065 52746197 1.64083515536950497115802830601E-16
245850922 78256779 7.81793661990795028841971693994E-17
411557987 131002976 1.93638047731304971158028306006E-17
657408909 209259755 1.71143721879895028841971693994E-17

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308500

To answer the question "why", it's because the most efficient floating point representation available on the majority of processors has a limited precision. It's 53 binary bits, or approximately 16 decimal digits.

Upvotes: 1

Noctis Skytower
Noctis Skytower

Reputation: 22041

As suggested by Diego Torres Milano, you should consider rewriting your code to use the decimal module (perhaps after some improvement to the original code that would help with readability and efficiency in its exeuction):

def main():
    pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
    numerator = 314
    denominator = 100
    print(numerator / denominator, numerator, denominator)
    best = 3
    while True:
        difference = abs(numerator / denominator - pi)
        next_numerator = numerator + 1
        next_pi = next_numerator / denominator
        next_difference = abs(next_pi - pi)
        if next_difference < difference:
            if next_difference < abs(best - pi):
                best = next_pi
                print(next_numerator, denominator, next_difference)
            numerator = next_numerator
        else:
            next_numerator = numerator - 1
            next_pi = next_numerator / denominator
            next_difference = abs(next_pi - pi)
            if next_difference < difference:
                if next_difference < abs(best - pi):
                    best = next_pi
                    print(next_numerator, denominator, next_difference)
                numerator = next_numerator
            else:
                denominator += 1


if __name__ == '__main__':
    main()

However, you might find that the fractions module would make a lot of sense to replace the numerator and denominator in your code as well. One advantage that Fraction objects have is that both halves are always kept in the lowest term.

Upvotes: -1

Diego Torres Milano
Diego Torres Milano

Reputation: 69388

You should use decimal, for example to get 1000 digits

>>> import decimal
>>> decimal.getcontext().prec = 1000 #1000 decimal precision
>>> decimal.getcontext().prec
1000
>>> decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571429')

Upvotes: 0

Related Questions