我遇到一个问题,即寻找2的平方根的二进制搜索算法似乎处于无限循环中并永远运行:
num = 2
low = 1
high = num
i = 0
while((i**2) != 2): #was while(low<high): but wasnt working with it either
i = low + (high - low) / 2;
sqrt = i * i
if (sqrt == num):
print(i)
elif(sqrt < num):
low = i
else:
high = i
print(sqrt)
testRoot = 2 ** (.5)
print(testRoot)
我不确定while循环是否存在问题。我认为这将是一个相当简单的二进制搜索算法,并进行了少许修改以适应平方根方面。
在运行代码时,我似乎无法获得任何输出。我不确定代码或编译器是否存在真正的问题,因为我以为我遵循的算法与过去非常接近。
答案 0 :(得分:5)
问题在于using ==
on floating point numbers几乎总是一个坏习惯,并且有v a r i o {{3} } u个问题。您应该用Procfile
代替比较。还要阅读这个问题下的评论,非常有用。
我修改后的代码如下(Python 3),如果想提高精度,请用较小的数字替换worker: python the_file_to_run.py
。但是请注意,“太精确”是不明智的,如果要停止循环,建议精度为abs(a - b) < precision
或更大,因为浮点数本身就有精度限制。
1e-6
答案 1 :(得分:2)
如my original comment和所有答案中所述,square root of 2是irrational。在这个问题上,不是整数的每个整数的平方根都是不合理的,因此2在这方面并不特殊。重要的是,x**2 == 2
对于任何x
的有限精度永远都不是正确的(因为有限精度是表示数字是有理数的另一种方式)。
其他答案建议您进行搜索,直到达到一定的固定预定精度为止。效果很好,特别是如果您提前知道答案的二进制数量级,那么您就可以将结果的精度设置为最后一位。
我想提出一种更自然的方法。您可以检查中心值是否正好等于边界之一。这意味着边界之间的差值的一半代表您当前猜测的精度不到一位数。您对中心的说法已经正确:可以使用i = low + (high - low) / 2
将low
与high
和==
进行比较,而i = (low + high) / 2
则不能。这是因为high - low
的精度大于或等于两个边界的精度,而low + high
可能会丢失一些数字。
这就是我的建议:
num = 2 low = 1 high = num guess = low + (high - low) / 2 count = 0 while guess != low and guess != high: sqr = guess * guess if sqr == num: break elif(sqr < num): low = guess else: high = guess guess = low + (high - low) / 2 count += 1 else: if abs(low * low - num) < abs(high * high - num): guess = low else: guess = high print(count, ':', sqr) print(num ** (.5), '~=', guess)
我已添加count
进行验证。结果是通过52次迭代获得的,精度在1位精度之内:
52 : 2.0000000000000004
1.4142135623730951 ~= 1.4142135623730951
对边界(else
的{{1}}子句)进行最终检查可确保您获得与期望结果最接近的结果,而无论您先打哪个。
收敛是理智的:64-bit floating point number in IEEE-754 format的尾数有53位,因此有意义的是您必须将搜索空间精确地减半多次才能获得结果(第一次是在循环之外) )。
这是我用于测试的代码段:https://ideone.com/FU9r82
答案 2 :(得分:1)
两个浮点数之间的相等是非常严格的条件,因为2的平方根在小数点后具有无数个数字。尝试以下while
条件:
while (abs((i ** 2) - 2) > 1e-8)
答案 3 :(得分:0)
进行一些探索通常会很有帮助。
MVVM/MVW
一些肘部润滑脂可以起到教育作用。 (而且令人困惑!)
让我们看一下错误
$ python
Python 3.6.6
>>> import math
>>> import numpy
>>> import scipy
>>> import numpy
>>> math.sqrt(2) ** 2
2.0000000000000004
>>> numpy.sqrt(2) ** 2
2.0000000000000004
>>> scipy.sqrt(2) ** 2
2.0000000000000004
>>> (2.0**(0.5))**2
2.0000000000000004
>>> x = math.sqrt(2) ** 2
>>> math.sqrt(x)
1.4142135623730951
>>> math.sqrt(2)
1.4142135623730951
>>> x*x
4.000000000000002
>>> x**2
4.000000000000002
>>> 1.414213562373095**2
1.9999999999999996
>>> 1.41421356237309505**2
2.0000000000000004
>>> 1.41421356237309505
1.4142135623730951
>>> 1.41421356237309504
1.4142135623730951
>>> 1.41421356237309504**2
2.0000000000000004
>>> 1.41421356237309503**2
1.9999999999999996
>>> 1.41421356237309503 * 1.41421356237309504
2.0
>>> 1.41421356237309504 - 1.41421356237309503
2.220446049250313e-16
答案 4 :(得分:0)
正如其他几篇文章所述,比较i * i == 2
无法正常工作。
设计停止标准的简单解决方案是告诉您想要多少精度。确实,在二分搜索中,精确位的数量在迭代中就增加了一个。
因此,要获得完全的双精度精度,请重复53次(更多的操作是没有用的)。还请注意,在循环内部测试相等性会适得其反。
num= 2
low= 1
hig= 2
for i in range(53):
mid= 0.5 * (low + hig)
if mid * mid < num:
low= mid
else:
hig= mid
print(mid)
在这里53次迭代是适当的,因为初始估计对于第一位(1≤√2<2)是准确的。对于不太准确的初始估算,请添加一些迭代。