我正在尝试使用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
答案 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], '+']