简体   繁体   English

使用二进制搜索在C中查找数字的平方根

[英]Using binary search to find the square root of a number in C

Trying to work out the square root of a number using binary search, however my implementation of it is not working and i'm not sure why - any help appreciated, thank you 试图使用二进制搜索计算出数字的平方根,但是我的实现不起作用,我不知道为什么 - 任何帮助表示赞赏,谢谢

Heres my code. 继承我的代码。 'end' being the value of the number I want to be square rooted 'end'是我希望平方根的数字的值

 while(start <= end) {
   float mid = ((start + end) / 2);
   printf("\nhalving mid");

   if(mid * mid == end){
      sqrt = mid;
      printf("\nsqrt = %d", sqrt);
   }
   if(mid * mid < end){
     start = mid + 1;
     sqrt = mid; 
     printf("\nsqrt: %d", sqrt);
   }
   else{
     start = mid - 1;
   }
 }

In addition to the logic problems in your code, it is not a good practice to compare floating point numbers. 除了代码中的逻辑问题之外,比较浮点数也不是一个好习惯。

mid * mid == end will probably always fail, even for sqrt(9) because it is very difficult to test floating-point numbers for equality . mid * mid == end可能总是会失败,即使对于sqrt(9)也是如此,因为测试浮点数是非常困难的

Look at this implementation using a range (epsil) instead of comparison: 使用范围(epsil)而不是比较来查看此实现:

static float my_sqrt(float num)
{
    double start = 0.0;
    double end = num;
    double sqrt = 0.0;
    double epsil = 0.000001;

    while (start <= end)
    {
        double mid = ((start + end) / 2);

        sqrt = mid;
        printf("sqrt = %f\n", sqrt);
        if (fabs(mid * mid -num) <= epsil)
        {
            break;
        }
        else if (mid * mid < num)
        {
            start = mid;
        }
        else
        {
            end = mid;
        }
    }
    return sqrt;
}

I am not fixingyour code, just explaining how I would write it. 我没有修复你的代码,只是解释我将如何写它。

Use an invariant that expresses the bracketing of the solution: 使用表示解决方案包围的不变量:

low² <= N < high²

Then taking an intermediate value mid , the test 然后取中间值mid ,测试

mid² <= N

allows to choose among 允许选择

low² <= N < mid² and mid² <= N < high²

and narrow down the search interval. 并缩小搜索间隔。

The iterations can stop when the search interval is a small as the floating-point representation allows (ie 23 bits for single precision). 当搜索间隔很小时,迭代可以停止,因为浮点表示允许(即单个精度为23位)。 You can stop when low == high . 你可以在low == high时停止。

To establish the invariant, 建立不变量,

low= 0, high= N

can do, provided that 0 <= N < N² . 只要0 <= N < N² ,就能做到。 This doesn't work when N <= 1 . N <= 1时,这不起作用。 A quick and dirty workaround is to set high= 1 . 快速而肮脏的解决方法是设置high= 1

low= 0
if N >= 1:
    high= N
else:
    high= 1

while low < high:
    mid= 0.5 * (low + high)
    if mid * mid <= N:
        high= mid
    else:
        low= mid

IMO, testing for equality mid² == N , then inequality mid² < N is counter-productive. IMO,测试mid² == N ,然后不等式mid² < N会适得其反。 You may be tempted to think that early termination when N is a perfect square allows to shorten the execution time. N是完美的正方形时,您可能会认为提前终止可以缩短执行时间。 But in reality, most of the input numbers are not perfect squares and you will be performing two tests instead of one, making the program slower on average. 但实际上,大多数输入数字都不是完美的正方形,你将进行两次测试而不是一次,这使得程序平均变慢。

Certainly the last line should be 当然最后一行应该是

 end = mid - 1;

conforming to the three cases 符合这三个案例

start..mid-1, mid, mid+1..end

And you should separate the number num that you want to compute the square root of and the end end of the search interval. 你应该将这个数num要计算平方根和最终end了搜索的时间间隔。


Of course you will also get a problem when the square root is not an integer. 当然,当平方根不是整数时,你也会遇到问题。 Then at some point it will fall inside one of the intervals (mid-1, mid) or (mid, mid+1) and thus outside of your algorithm. 然后在某个时刻它将落入其中一个间隔(mid-1, mid)(mid, mid+1) ,因此在算法之外。

Thus you need to separate the cases as 因此,您需要将案例分开

[start, mid] (mid, mid+1), [mid+1,end]

if you want to stay with integer boundaries. 如果你想保持整数边界。 The middle case is 中间案例是

 ( mid*mid> num ) && ( (mid+1)*(mid+1) < num )
public int sqrt(int x) {
    if (x == 0)
        return 0;
    int left = 1, right = Integer.MAX_VALUE;
    while (true) {
        int mid = left + (right - left)/2;
        if (mid > x/mid) {
            right = mid - 1;
        } else {
            if (mid + 1 > x/(mid + 1))
                return mid;
            left = mid + 1;
        }
    }
}

You should replace your last line with 你应该用你的最后一行替换

end = mid -1

in the else snippet 在else片段中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM