平方根的逐位数计算限制

时间:2015-04-19 01:47:31

标签: algorithm python-3.x

我正在尝试使用Python中的Chudnovsky算法获得尽可能好的pi估计值。该算法意味着获得640 320的平方根。

经过一些研究,我发现了一种计算平方根的非常有效的方法;该方法称为“逐位计算”(参见here)。因此,在尝试实现它之后,我发现前13个小数是正确的,然后我得到奇怪的结果(下一个是0而不是4,然后下一个'数字'是128,然后-1024 ...)

我试过检查我的功能,但它看起来很好(除此之外,我可能不会找到正确的前13位小数)。因此,我的问题是:这种逐位计算方法有一些限制吗?

如果您希望看到我的代码,那么它是:

def sqrt(input_number,accuracy):
"""input_number is a list that represents a number we want to get the square root of.
For example, 12.56 would be [[1,2], [5,6], '+']"""
    
    if input_number[2]!="+":
        raise ValueError("Cannot find the real square root of a negative number: '"+pl(input_number)+"'")
    
"""Below creates the right number of elements for the required accuracy of the
square root"""
    if len(input_number[0])%2==1:
        input_number[0].insert(0,0)
        
    if len(input_number[1])<2*accuracy:
        for i in range(2*accuracy-len(input_number[1])):
            input_number[1].append(0)
            
    if len(input_number[1])%2==1:
        input_number[1].append(0)
    
# Below makes the pairs of digits required in the algorithm
    pairs=[[10*input_number[0][2*i]+input_number[0][2*i+1] for i in range(int(len(input_number[0])/2))],[10*input_number[1][2*i]+input_number[1][2*i+1] for i in range(int(len(input_number[1])/2))]]

    
"""Performs the algorithm, where c,x,y and p have the same definition
as on the Wikipedia link above. r is the remainder. pairs[0] is the pairs
of digits before the decimal dot, and pairs[1] represents the pairs of
digits after the dot. square_root is the computed square root of input_number."""
    p=0
    r=0
    square_root=[[],[],"+"]
    for i in range(len(pairs[0])):
        c=100*r+pairs[0][i]
        x=int((-20*p+(400*p**2+4*c)**.5)/2)
        y=20*p*x+x**2
        r=c-y
        p=10*p+x
        square_root[0].append(x)
    
    for i in range(len(pairs[1])):
        print(p,r,c)
        c=100*r+pairs[1][i]
        x=int((-20*p+(400*p**2+4*c)**.5)/2)
        y=20*p*x+x**2
        r=c-y
        p=10*p+x
        square_root[1].append(x)
    
    
    return square_root

1 个答案:

答案 0 :(得分:1)

问题在于此代码。

x = int((-20 * p + (400 * p ** 2 + 4 * c) ** .5) / 2)

此代码执行浮点减法。它会导致重要性的丧失,因为减去了两个接近的数字。

>>> p = 10**15
>>> c = 10**15
>>> x = (-20 * p + (400 * p ** 2 + 4 * c) ** .5) / 2
>>> x
0.0

所以,你应该使用整数sqrt而不是**.5。并像这样改变循环。

for i in range(len(pairs[0])):
    c = 100 * r + pairs[0][i]
    #x = int((-20 * p + (400 * p ** 2 + 4 * c) ** .5) / 2)
    x = (-20 * p + isqrt(400 * p ** 2 + 4 * c)) // 2
    y = 20 * p * x + x ** 2
    r = c - y
    p = 10 * p + x
    square_root[0].append(x)

for i in range(len(pairs[1])):
    #print(p,r,c)
    c = 100 * r + pairs[1][i]
    #x = int((-20 * p + (400 * p ** 2 + 4 * c) ** .5) / 2)
    x = (-20 * p + isqrt(400 * p ** 2 + 4 * c)) // 2
    y = 20 * p * x + x ** 2
    r = c - y
    p = 10 * p + x
    square_root[1].append(x)

并定义isqrt - 整数sqrt函数

# from http://stackoverflow.com/questions/15390807/integer-square-root-in-python
def isqrt(n):
    x = n
    y = (x + 1) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

然后,你可以获得一个sqrt值(2)。

>>> print( sqrt([[2], [0], '+'], 25) )
[[1], [4, 1, 4, 2, 1, 3, 5, 6, 2, 3, 7, 3, 0, 9, 5, 0, 4, 8, 8, 0, 1, 6, 8, 8, 7], '+']