二进制搜索平方根2

时间:2018-09-05 02:19:27

标签: python binary-search numerical-methods square-root

我遇到一个问题,即寻找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循环是否存在问题。我认为这将是一个相当简单的二进制搜索算法,并进行了少许修改以适应平方根方面。

在运行代码时,我似乎无法获得任何输出。我不确定代码或编译器是否存在真正的问题,因为我以为我遵循的算法与过去非常接近。

5 个答案:

答案 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 2irrational。在这个问题上,不是整数的每个整数的平方根都是不合理的,因此2在这方面并不特殊。重要的是,x**2 == 2对于任何x的有限精度永远都不是正确的(因为有限精度是表示数字是有理数的另一种方式)。

其他答案建议您进行搜索,直到达到一定的固定预定精度为止。效果很好,特别是如果您提前知道答案的二进制数量级,那么您就可以将结果的精度设置为最后一位。

我想提出一种更自然的方法。您可以检查中心值是否正好等于边界之一。这意味着边界之间的差值的一半代表您当前猜测的精度不到一位数。您对中心的说法已经正确:可以使用i = low + (high - low) / 2lowhigh==进行比较,而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)是准确的。对于不太准确的初始估算,请添加一些迭代。