[技术问答] 单片机开平方的快速算法 (2)

[复制链接]
11|1
lzmm 发表于 2026-3-26 21:03 | 显示全部楼层 |阅读模式
1.原理  
因为排版的原因,用pow(X,Y)表示X的Y次幂,用B[0],B[1],...,B[m-1]表示一个序列,  
其中[x]为下标。  

假设:  
   B[x],b[x]都是二进制序列,取值0或1。  
   M = B[m-1]*pow(2,m-1) + B[m-2]*pow(2,m-2) + ... + B[1]*pow(2,1) + B[0]*pow  
(2,0)  
   N = b[n-1]*pow(2,n-1) + b[n-2]*pow(2,n-2) + ... + b[1]*pow(2,1) + n[0]*pow  
(2,0)  
   pow(N,2) = M  

   (1) N的最高位b[n-1]可以根据M的最高位B[m-1]直接求得。  
   设 m 已知,因为 pow(2, m-1) <= M <= pow(2, m),所以 pow(2, (m-1)/2) <= N <=  
pow(2, m/2)  
   如果 m 是奇数,设m=2*k+1,  
   那么 pow(2,k) <= N < pow(2, 1/2+k) < pow(2, k+1),  
   n-1=k, n=k+1=(m+1)/2  
   如果 m 是偶数,设m=2k,  
   那么 pow(2,k) > N >= pow(2, k-1/2) > pow(2, k-1),  
   n-1=k-1,n=k=m/2  
   所以b[n-1]完全由B[m-1]决定。  
   余数 M[1] = M - b[n-1]*pow(2, 2*n-2)  

   (2) N的次高位b[n-2]可以采用试探法来确定。  
   因为b[n-1]=1,假设b[n-2]=1,则 pow(b[n-1]*pow(2,n-1) + b[n-1]*pow(2,n-2),  
2) = b[n-1]*pow(2,2*n-2) + (b[n-1]*pow(2,2*n-2) + b[n-2]*pow(2,2*n-4)),  
   然后比较余数M[1]是否大于等于 (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4)。这种  
比较只须根据B[m-1]、B[m-2]、...、B[2*n-4]便可做出判断,其余低位不做比较。  
   若 M[1] >= (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设有效,b[n-2] =  
1;  
   余数 M[2] = M[1] - pow(pow(2,n-1)*b[n-1] + pow(2,n-2)*b[n-2], 2) = M[1] -  
(pow(2,2)+1)*pow(2,2*n-4);  
   若 M[1] < (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设无效,b[n-2] =  
0;余数 M[2] = M[1]。  

   (3) 同理,可以从高位到低位逐位求出M的平方根N的各位。  

使用这种算法计算32位数的平方根时最多只须比较16次,而且每次比较时不必把M的各位逐  
一比较,尤其是开始时比较的位数很少,所以消耗的时间远低于牛顿迭代法。  


2. 实现代码  
这里给出实现32位无符号整数开方得到16位无符号整数的C语言代码。  

  1. 1.原理  
  2. 因为排版的原因,用pow(X,Y)表示X的Y次幂,用B[0],B[1],...,B[m-1]表示一个序列,  
  3. 其中[x]为下标。  

  4. 假设:  
  5.    B[x],b[x]都是二进制序列,取值0或1。  
  6.    M = B[m-1]*pow(2,m-1) + B[m-2]*pow(2,m-2) + ... + B[1]*pow(2,1) + B[0]*pow  
  7. (2,0)  
  8.    N = b[n-1]*pow(2,n-1) + b[n-2]*pow(2,n-2) + ... + b[1]*pow(2,1) + n[0]*pow  
  9. (2,0)  
  10.    pow(N,2) = M  

  11.    (1) N的最高位b[n-1]可以根据M的最高位B[m-1]直接求得。  
  12.    设 m 已知,因为 pow(2, m-1) <= M <= pow(2, m),所以 pow(2, (m-1)/2) <= N <=  
  13. pow(2, m/2)  
  14.    如果 m 是奇数,设m=2*k+1,  
  15.    那么 pow(2,k) <= N < pow(2, 1/2+k) < pow(2, k+1),  
  16.    n-1=k, n=k+1=(m+1)/2  
  17.    如果 m 是偶数,设m=2k,  
  18.    那么 pow(2,k) > N >= pow(2, k-1/2) > pow(2, k-1),  
  19.    n-1=k-1,n=k=m/2  
  20.    所以b[n-1]完全由B[m-1]决定。  
  21.    余数 M[1] = M - b[n-1]*pow(2, 2*n-2)  

  22.    (2) N的次高位b[n-2]可以采用试探法来确定。  
  23.    因为b[n-1]=1,假设b[n-2]=1,则 pow(b[n-1]*pow(2,n-1) + b[n-1]*pow(2,n-2),  
  24. 2) = b[n-1]*pow(2,2*n-2) + (b[n-1]*pow(2,2*n-2) + b[n-2]*pow(2,2*n-4)),  
  25.    然后比较余数M[1]是否大于等于 (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4)。这种  
  26. 比较只须根据B[m-1]、B[m-2]、...、B[2*n-4]便可做出判断,其余低位不做比较。  
  27.    若 M[1] >= (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设有效,b[n-2] =  
  28. 1;  
  29.    余数 M[2] = M[1] - pow(pow(2,n-1)*b[n-1] + pow(2,n-2)*b[n-2], 2) = M[1] -  
  30. (pow(2,2)+1)*pow(2,2*n-4);  
  31.    若 M[1] < (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设无效,b[n-2] =  
  32. 0;余数 M[2] = M[1]。  

  33.    (3) 同理,可以从高位到低位逐位求出M的平方根N的各位。  

  34. 使用这种算法计算32位数的平方根时最多只须比较16次,而且每次比较时不必把M的各位逐  
  35. 一比较,尤其是开始时比较的位数很少,所以消耗的时间远低于牛顿迭代法。  


  36. 2. 实现代码  
  37. 这里给出实现32位无符号整数开方得到16位无符号整数的C语言代码。  


野玫瑰 发表于 2026-4-22 10:56 | 显示全部楼层
二分法通过区间逼近求整数平方根,无浮点、速度稳、代码极简。设低 = 0、高 = 输入值,循环取中值平方与原数比较,缩小区间直至高低收敛。无乘法器也极快,仅加减移位,适配 8 位单片机;比逐次逼近省代码、比牛顿法易实现,结果为整数平方根,满足仪表、控制等嵌入式需求。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

421

主题

9417

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部
0