zoukankan      html  css  js  c++  java
  • 利用移位、加减法实现整数开平方算法的方法(转)

    本算法只采用移位、加减法、判断和循环实现,因为它不需要浮点运算,也不需要乘除运算,因此可以很方便地运用到各种芯片上去。

    我们先来看看10进制下是如何手工计算开方的。
    先看下面两个算式,
    x = 10*p + q  (1)
    公式(1)左右平方之后得:
    x^2 = 100*p^2 + 20pq + q^2 (2)
    现在假设我们知道x^2和p,希望求出q来,求出了q也就求出了x^2的开方x了。
    我们把公式(2)改写为如下格式:
    q = (x^2 - 100*p^2)/(20*p+q) (3)

    这个算式左右都有q,因此无法直接计算出q来,因此手工的开方算法和手工除法算法一样有一步需要猜值。

    我们来一个手工计算的例子:计算1234567890的开方

    首先我们把这个数两位两位一组分开,计算出最高位为3。也就是(3)中的p,最下面一行的334为余数,也就是公式(3)中的(x^2 - 100*p^2)近似值
        3
      ---------------
     / 12 34 56 78 90
        9
      ---------------
     /  3 34

    下面我们要找到一个0-9的数q使它最接近满足公式(3)。我们先把p乘以20写在334左边:
                               3  q
                             ---------------
                            / 12 34 56 78 90
                               9
                             ---------------
    (20*3+q)*q      /  3 34

    我们看到q为5时(60+q)*q的值最接近334,而且不超过334。于是我们得到:
          3  5
        ---------------
       / 12 34 56 78 90
          9
        ---------------
    65 /  3 34
          3 25
        ---------------
             9 56

    接下来就是重复上面的步骤了,这里就不再啰嗦了。

    这个手工算法其实和10进制关系不大,因此我们可以很容易的把它改为二进制,改为二进制之后,公式(3)就变成了:
    q = (x^2 - 4*p^2)/(4*p+q) (4)

    我们来看一个例子,计算100(二进制1100100)的开方:
           1  0  1  0
          -----------
         / 1 10 01 00
           1
          -----------
     100 / 0 10 
           0 00 
          -----------
    1001 /   10 01
             10 01
          -----------
              0 00

    这里每一步不再是把p乘以20了,而是把p乘以4,也就是把p右移两位,而由于q的值只能为0或者1,所以我们只需要判断余数(x^2 - 4*p^2)和(4*p+1)的大小关系,如果余数大于等于(4*p+q)那么该上一个1,否则该上一个0。

    下面给出完成的C语言程序,其中root表示p,rem表示每步计算之后的余数,divisor表示(4*p+1),通过a>>30取a的最高 2位,通过a<<=2将计算后的最高2位剔除。其中root的两次<<1相当于4*p。程序完全是按照手工计算改写的,应该不难理解。
    unsigned short sqrt(unsigned long a){
      unsigned long rem = 0;
      unsigned long root = 0;
      unsigned long divisor = 0;
      for(int i=0; i<16; ++i){
        root <<= 1;
        rem = ((rem << 2) + (a >> 30));
        a <<= 2;
        divisor = (root<<1) + 1;
        if(divisor <= rem){
          rem -= divisor;
          root++;
        }
      }
      return (unsigned short)(root);
    }

    posted on 2008-01-23 14:21 QUIRE-0216 阅读(2127) 评论(1)  编辑 收藏 引用 所属分类: Arithmetic(算法)

    Feedback

    # re: 利用移位、加减法实现整数开平方算法的方法(转) 2008-01-23 14:46 QUIRE-0216
    为了大家能理解我把上面 1234567890 给做完! 
                  3 5 q 
                   --------------- 
                   / 12 34 56 78 90 
                   9 
                   --------------- 
                   65 / 3 34 
                   3 25 
                   --------------- 
    (20*35+q)*q /  9 56 
    我们看到q为1时(700+q)*q的值最接近956,而且不超过956。于是我们得到: 
                  3 5 1 q 
                   --------------- 
                   / 12 34 56 78 90 
                   9 
                   --------------- 
                   65 / 3 34 
                   3 25 
                   --------------- 
    701 /   9 56 
    7 01 
    ---------------- 
    (20*351+q)*q / 2 55 78 

    我们看到q为3时(20*351+q)*q的值最接近25578,而且不超过25578。于是我们得到: 

                  3 5 1 3 q 
                   --------------- 
                   / 12 34 56 78 90 
                   9 
                   --------------- 
                   65 / 3 34 
                   3 25 
                   --------------- 
    701 /   9 56 
    7 01 
    ---------------- 
    7023 / 2 55 78 
    2 10 69 
    ---------------- 
    (20*3513+q)*q / 45 0990 

    我们看到q为6时(20*3513+q)*q的值最接近450990,而且不超过450990。于是我们得到: 
                  3 5 1 3 6 
                   --------------- 
                   / 12 34 56 78 90 
                   9 
                   --------------- 
                   65 / 3 34 
                   3 25 
                   --------------- 
    701 /   9 56 
    7 01 
    ---------------- 
    7023 / 2 55 78 
    2 10 69 
    ---------------- 
    70266 / 45 0990 
    42 1596 
    ---------------- 
    2 9394 

    至此1234567890的根为35136.我想能看明白吧! 
  • 相关阅读:
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale
    CodeForces 785B Anton and Classes
    CodeForces 785A Anton and Polyhedrons
    爱奇艺全国高校算法大赛初赛C
    爱奇艺全国高校算法大赛初赛B
    爱奇艺全国高校算法大赛初赛A
    EOJ 3265 七巧板
    EOJ 3256 拼音魔法
    EOJ 3262 黑心啤酒厂
  • 原文地址:https://www.cnblogs.com/socquan/p/4578673.html
Copyright © 2011-2022 走看看