Reputation: 1
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.
Upvotes: -3
Views: 110
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
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
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
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