def pi():
prompt=">>> "
print "\nWARNING: Pi may take some time to be calculated and may not always be correct beyond 100 digits."
print "\nShow Pi to what digit?"
n=raw_input(prompt)
from decimal import Decimal, localcontext
with localcontext() as ctx:
ctx.prec = 10000
pi = Decimal(0)
for k in range(350):
pi += (Decimal(4)/(Decimal(8)*k+1) - Decimal(2)/(Decimal(8)*k+4) - Decimal(1)/(Decimal(8)*k+5) - Decimal(1)/(Decimal(8)*k+6)) / Decimal(16)**k
print pi[:int(n)]
pi()
Traceback (most recent call last):
File "/Users/patrickcook/Documents/Pi", line 13, in <module>
pi()
File "/Users/patrickcook/Documents/Pi", line 12, in pi
print pi[:int(n)]
TypeError: 'Decimal' object has no attribute '__getitem__'
You are trying to treat pi
as an array, when it is a Decimal
. I think you are looking for quantize
:https://docs.python.org/2/library/decimal.html
I got bored with how long the process it was taking (that 350-iteration loop is a killer), but the answer seems plain. A Decimal
object is not subscriptable the way you have it.
You probably want to turn it into a string first and then process that to get the digits:
print str(pi)[:int(n)+1] # ignore decimal point in digit count.
You should also keep in mind that this truncates the value rather than rounding it. For example, with PI starting out as:
3.141592653589
(about as much as I can remember off the top of my head), truncating the string at five significant digits will give you 3.1415
rather than the more correct 3.1416
.
If you'd like a faster pi algorithm, try this one. I've never used the Decimal module before; I normally use mpmath for arbitrary precision calculations, which comes with lots of functions, and built-in "constants" for pi and e. But I guess Decimal is handy because it's a standard module.
''' The Salamin / Brent / Gauss Arithmetic-Geometric Mean pi formula.
Let A[0] = 1, B[0] = 1/Sqrt(2)
Then iterate from 1 to 'n'.
A[n] = (A[n-1] + B[n-1])/2
B[n] = Sqrt(A[n-1]*B[n-1])
C[n] = (A[n-1]-B[n-1])/2
PI[n] = 4A[n+1]^2 / (1-(Sum (for j=1 to n; 2^(j+1))*C[j]^2))
See http://stackoverflow.com/q/26477866/4014959
Written by PM 2Ring 2008.10.19
Converted to use Decimal 2014.10.21
Converted to Python 3 2018.07.17
'''
import sys
from decimal import Decimal as D, getcontext, ROUND_DOWN
def AGM_pi(m):
a, b = D(1), D(2).sqrt() / 2
s, k = D(0), D(4)
for i in range(m):
c = (a - b) / 2
a, b = (a + b) / 2, (a * b).sqrt()
s += k * c * c
#In case we want to see intermediate results
#if False:
#pi = 4 * a * a / (1 - s)
#print("%2d:\n%s\n" % (i, pi))
k *= 2
return 4 * a * a / (1 - s)
def main():
prec = int(sys.argv[1]) if len(sys.argv) > 1 else 50
#Add 1 for the digit before the decimal point,
#plus a few more to compensate for rounding errors.
#delta == 7 handles the Feynman point, which has six 9s followed by an 8
delta = 3
prec += 1 + delta
ctx = getcontext()
ctx.prec = prec
#The precision of the AGM value doubles on every loop
pi = AGM_pi(prec.bit_length())
#Round down so all printed digits are (usually) correct
ctx.rounding = ROUND_DOWN
ctx.prec -= delta
print("pi ~=\n%s" % +pi)
if __name__ == '__main__':
main()
A Decimal
object can't be sliced to get the individual digits. However a string can, so convert it to a string first.
print str(pi)[:int(n)]
You may need to adjust n
for the decimal point and desired digit range.
来源:https://stackoverflow.com/questions/26477866/i-am-attempting-to-print-only-a-selected-amount-of-pi-it-returns-with-an-error