-->

I am attempting to print only a selected amount of

2020-02-07 13:14发布

问题:

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__'

回答1:

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



回答2:

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.



回答3:

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()


回答4:

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.