平方根的C语言实现(二) —— 手算平方根的原理

  一个函数从数学上来说可以有无数个函数列收敛于这个函数,那么程序逼近实现来说可以有无数种算法,平方根自然也不例外。

  不知道有多少人还记得手算平方根,那是满足每次在结果上添加一位,也就是按位逼近运算结果的唯一算法。至于数学上如何证明这个唯一性我就不说了,数学证明不会有那么多人有兴趣。按位逼近更加适合手算,举个大家更熟悉的例子,那就是手算除法。我这里就采用按位逼近的手算方法。

  要说手算平方根,原理其实非常简单,

  一是平方根函数是严格单调增函数,

  二就是以下这个恒等式满足

  (a*N+b)≡ (a*N)+ 2*a*b*N + b2

      ≡ (a*N)+ b * ((a*N) * 2 + b)

  我们实例操作一次平方根笔算,来解释一下。

  我们来求5499025的平方根。

  先将5499025两位两位从低往高排,为

  5 49 90 25

  2*2<5<3*3

  所以最高位为2,

  然后我们再来看549的平方根,

  我们假设549的平方根的整数部分是2*10+b,则根据之前的恒等式,N在这里等于10,a在这里等于2,有

  549 >=(2*10)+ b * ((2*10) * 2 + b)

  整理一下,149 >= b * (40 + b)

  3 * 43 < 149 < 4 * 44

  所以b=3,

  549的平方根整数部分是23,

  再假设54990的平方根整数部分为23*10+b,

  则

  54990 >= (23*10)+ b * ((23*10) * 2 + b)

  整理一下,2090 >= b * (460 + b),

  464 * 4  < 2090 < 465 * 5

  所以b=4,

  54990的平方根整数部分为234,

  最后再来看5499025的平方根的整数部分,假设为234 * 10 + b,

  则

  5499025 >=  (234*10)+ b * ((234*10) * 2 + b)

  整理一下, 23425 >= b * (4680 + b)

  而5 * 4685 = 23425, 等式成立,

  所以最终我们要求的平方根是2345。当然,小数位其实一样可以用这种方法继续算下去。

  手算平方根就是如上这样从高位一步步往地位推的过程,写成式子的形式大致如下:

   2    3     4     5

  -------------------

   | 5   49   90   25

2 | 4

  -------------------

| 1  49

43 | 1  29      ——当前算出了2,2*10*2 = 40

-------------------

|  20   90

464 |  18   56    ——当前算出了23,23*10*2 = 460

-------------------

|  2   34   25

4685  |  2   34   25  ——当前算出了234,234*10*2 = 4680

-------------------

0

  当然,如何写不重要,知道过程便可以继续我们的这个设计。接下去我们要去利用之前的这个算法,改装一下,来进行二进制的开平方。

  二进制的每一位不是1就是0,这样在每次往前推一位的时候就相对简单。

  举个例子,我们来算121的平方根,也就是二进制下1111001的平方根。

  两位两位从低位往高位排

1   0    1     1

  ------------------

| 1  11  10  01

1 | 1

  ------------------

    | 11

100 |   0                  ——当前上面算出了1,1右移动两位为100

  ------------------

    | 11  10

1001 | 10  01           ——当前上面算出了10,1右移动两位为1000

  ------------------

| 1 01  01

10101 | 1 01 01     ——当前上面算出了101,1右移动两位为10100

  ------------------

0

每往右边推1位,下面的除数就是上面当前算出来的二进制的数右移两位再加1或者加0

之后,我们就可以用构建利用此算法的平方根了。

时间: 2024-08-03 22:47:36

平方根的C语言实现(二) —— 手算平方根的原理的相关文章

平方根的C语言实现(三) ——最终程序实现

了解了浮点数的存储以及手算平方根的原理,我们可以考虑程序实现了. 先实现一个64位整数的平方根,根据之前的手算平方根,程序也不是那么难写了. #include <stdint.h>uint64_t _sqrt_u64(uint64_t a) { int i; uint64_t res; uint64_t remain; //0的平方根是0,特殊处理一下 if(a == 0ull) return 0ull; //找到最高位的1,并且产生平方根结果最高位的1 for(i=62;;i-=2) if(

手算平方根的正确方法

手算平方根的「正确」方法,是什么方法?如果你认为是牛顿迭代法的话,你可以亲自试一下,看看效果如何: (原帖 kz3007407872, 鉴于百度贴吧的帖子是公开的,我就不打码了) 其实牛顿迭代法非常好,在电脑上快得飞起.但是手算就不行了. 那么「正确」的方法是什么呢?是这个: (原帖同上) 说得神神叨叨的,还能开无限小数,到底是什么方法?帖子里没说. 不过,幸运的是,我有一天翻 Wiki 的时候,碰巧翻到了这个方法.本文将详细介绍这个方法. \(2\) 的算术平方根是多少?是 \(\sqrt{2

UVA 10023 - Square root(手算平方根)

题目:UVA 10023 - Square root(手算平方根) 题目链接 题目大意:求给定的一个数的平方根. 解题思路:用二分但是这个数太大了,就超时了.看题接后发现需要用一种手算平方根的算法. 算法: 先判断这个数是不是偶数位,是的话就第一次取前面的两位数,不是的话第一次就只取前面的一位数来作为被除数.接下来就是两位两位为一节来计算. 用前一次的计算结果乘上20+一个个位数a再乘上这个a,找到最大的a使得这个式子的结果不大于被除数. 被除数减去这个结果然后再在尾巴接上那个大数的接下来两位作

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

嵌入式linux面试题解析(二)——C语言部分二

嵌入式linux面试题解析(二)--C语言部分二 1..h头文件中的ifndef/define/endif 的作用?    答:防止该头文件被重复引用. 2.#include 与 #include "file.h"的区别?    答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h. 3.描述实时系统的基本特性    答 :在特定时间内完成特定的任务,实时性与可靠性. 4.全局变量和局部变量在内存中是否有区别?如果有,是

R语言基础(二) 可视化基础

> which.max(apply(x[c("x1","x2","x3")], 1, sum))49 > x$num[which.max(apply(x[c("x1","x2","x3")], 1, sum))][1] 2005138149 > hist(x$x1) > plot(x$x1,x$x2) > table(x$x1) 80 81 82 83 84

Swift语言指南(二)--语言基础之注释和分号

注释 通过注释向自己的代码中注入不可执行的文本,作为你自己的笔记或提示.Swift编译器运行时会忽略注释. Swift的注释与C语言极其相似,单行注释以两个反斜线开头: //这是一行注释 多行注释以/*开始,以*/结束: ? 1 2 3 <span style="color: rgb(0, 128, 0);">/* 这也是一条注释, 但跨越多行 */ </span> 与 C 语言的多行注释有所不同的是,Swift 的多行注释可以嵌套在其他多行注释内部.写法是在一

C语言动态分配二维数组内存

C语言内存管理主要包括malloc().remalloc().free()三个函数. malloc原型 extern void *malloc(unsigned int num_bytes); m行n列的 二维数组的分配,主要有三种方法: 一.分配一个长度为m的二级指针,指针的指向的内容分别指向一个长度为n的一位数组 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h>

边看MHA源码边学Perl语言之二 ManagerUtil

边看MHA源码边学Perl语言之二ManagerUtil.pm MHA版本 为了让大家有一个共同的代码学习环境,特别从网络找了mha4mysql-manager-0.56,mha4mysql-node-0.56稳定版作为学习和研究对象,大家可以到直接到github上进行clone: https://github.com/mysql-dev-fun/mha4mysql-manager-0.56 https://github.com/mysql-dev-fun/mha4mysql-node-0.56