【问题标题】:Using binary search to find the square root of a number in C使用二分搜索在 C 中找到数字的平方根
【发布时间】:2016-11-28 16:45:19
【问题描述】:

尝试使用二进制搜索计算数字的平方根,但是我的实现不起作用,我不知道为什么 - 任何帮助表示感谢,谢谢

这是我的代码。 '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;
   }
 }

【问题讨论】:

  • 您的代码 sn-p 中的输入究竟是什么?
  • 没有输入我将它用作平方根函数,其中'end'是我想要找到平方根的数字
  • 您的代码将打印小于平方根的值,继续直接命中,并陷入无限循环。很抱歉不得不告诉你这一点,但你必须先完成一些简单的练习,然后再尝试。
  • 如果这不仅仅是为了好玩或训练,请使用收敛速度更快的牛顿迭代。 (暂时忽略 Math.sqrt)。
  • 使用调试器或打印每个步骤中的间隔结束,以查看为什么您的实现动态会在某个时候停止。升一降一,无限重复。

标签: c algorithm math


【解决方案1】:

除了代码中的逻辑问题之外,比较浮点数并不是一个好习惯。

mid * mid == end 可能总是会失败,即使对于 sqrt(9),因为it is very difficult to test floating-point numbers for equality

使用范围(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;
}

【讨论】:

  • 你有什么特殊原因不使用float.h中的DBL_EPSILON吗?
  • 这个想法是为了表明精度掌握在程序员的手中。这听起来是个好主意。
【解决方案2】:

我不是在修改你的代码,只是解释我将如何编写它。

使用表示解决方案的括号的不变量:

low² <= N < high²

然后取一个中间值mid,进行测试

mid² <= N

允许选择

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

并缩小搜索间隔。

当搜索间隔很小时,迭代可以停止,因为浮点表示允许(即单精度为 23 位)。你可以在low == high时停下来。

要建立不变量,

low= 0, high= N

可以,前提是0 &lt;= N &lt; N²。这在N &lt;= 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,测试相等 mid² == N,然后不相等 mid² &lt; N 会适得其反。您可能会认为当N 是一个完美的正方形时提前终止可以缩短执行时间。但实际上,大多数输入数字都不是完美的平方,您将执行两个测试而不是一个,这会使程序平均变慢。

【讨论】:

    【解决方案3】:

    当然最后一行应该是

     end = mid - 1;
    

    符合三种情况

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

    您应该将要计算平方根的数字num 与搜索间隔的结尾end 分开。


    当然,当平方根不是整数时,您也会遇到问题。然后在某个时候,它会落在(mid-1, mid)(mid, mid+1) 的区间之一内,因此不在您的算法范围内。

    因此您需要将案例分开为

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

    如果你想保持整数边界。中间情况是

     ( mid*mid> num ) && ( (mid+1)*(mid+1) < num )
    

    【讨论】:

    • 当然,当平方根不是整数时,你会遇到问题。
    • 如果在算法过程中更改输入,也会得到无意义的结果。将搜索期间保持不变的输入与搜索间隔的变量端分开。
    【解决方案4】:

    你应该用

    替换你的最后一行
    end = mid -1
    

    在else sn-p中

    【讨论】:

      【解决方案5】:
      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;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-09-08
        • 1970-01-01
        • 1970-01-01
        • 2011-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多