[英]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.