本文从属于笔者的数据结构与算法系列文章。

SquareRoot

平方根计算一直是计算系统的常用算法,本文列举出几张简单易懂的平方根算法讲解与实现。其中Java版本的代码参考这里

Reference

  • 计算平方根的算法

  • Wiki-Methods of computing square roots

Babylonian:巴比伦算法/牛顿法

巴比伦算法可能算是最早的用于计算$sqrt{S}$的算法之一,因为其可以用牛顿法导出,因此在很多地方也被成为牛顿法。其核心思想在于为了计算x的平方根,可以从某个任意的猜测值g开始计算。在真实的运算中,我们往往将g直接设置为x,不过也可以选择其他任何的正数值。那么其计算的迭代过程为:

1.如果猜测值g已经足够接近于正确的平方根,算法结束,函数将g作为结果返回。

2.如果猜测值g不够精确,那么使用gx/g的平均值作为新的猜测值。因为这两个值中的一个小于确切的平方根,另一个则大于确切的平方根,选择平均值有助于你得到一个更接近于正确答案的值。

3.把新的猜测值赋予给变量g,重复第一步的判断。

综上所述,其计算公式可以表述为:

其实现的参考代码地址为SquareRoots:


public double Babylonian() {double g = this.value;while (isApproximate(g)) {g = (g + this.value / g) / 2;}return g;}

基于泰勒公式的级数逼近

微积分中的泰勒级数可以表示为:

在这个公式中,符号a表示某个常量,记号f'、f''f'''表示函数f的一阶、二阶和三阶导数,以此类推,这个公式称为泰勒公式,基于这个公式,我们平方根公式的展开式为:

根据该公式我们可以在一定精度内逼近真实值,不过这个公式仍然存在一个问题,即是公式的收敛问题。在泰勒级数展开中,平方根函数的公式当且仅当参数值位于一个有效范围内时才有效,在该范围内计算趋于收敛。该范围即是收敛半径,当我们对平方根函数用a=1进行计算时,泰勒级数公式希望x处于范围:$0<x<2$之间。如果x在收敛半径之外,则展开式中的项会越来越大,泰勒级数离答案也就越来越远。为了解决该问题,我们可以考虑当待开平方数大于4时以4去除它,最后将得到的数乘以相同次数的2即可。其实现的参考代码地址为SquareRoots:


public double TSqrt() {//设置修正系数double correction = 1;//因为要对原值进行缩小,因此设置临时值double tempValue = value;while (tempValue >= 2) {tempValue = tempValue / 4;correction *= 2;}return this.TSqrtIteration(tempValue) * correction;
}private double TSqrtIteration(double value) {double sum = 0, coffe = 1, factorial = 1, xpower = 1, term = 1;int i = 0;while (Math.abs(term) > 0.000001) {sum += term;coffe *= (0.5 - i);factorial *= (i + 1);xpower *= (value - 1);term = coffe * xpower / factorial;i++;}return sum;}

平方根倒数速算法

首先接收一个32位带符浮点数,然后将之作为一个32位整数看待,以将其向右进行一次逻辑移位的方式将之取半,并用十六进制“魔术数字”0x5f3759df减之,如此即可得对输入的浮点数的平方根倒数的首次近似值;而后重新将其作为浮点数,以牛顿法反复迭代,以求出更精确的近似值,直至求出符合精确度要求的近似值。在计算浮点数的平方根倒数的同一精度的近似值时,此算法比直接使用浮点数除法要快四倍。此算法最早被认为是由约翰·卡马克所发明,但后来的调查显示,该算法在这之前就于计算机图形学的硬件与软件领域有所应用,如SGI和3dfx就曾在产品中应用此算法。而就现在所知,此算法最早由Gary Tarolli在SGI Indigo的开发中使用。虽说随后的相关研究也提出了一些可能的来源,但至今为止仍未能确切知晓此常数的起源。

其实现的参考代码地址为SquareRoots:

public double FastInverseSquareRoot() {double tempValue = value;double xhalf = 0.5d * tempValue;long i = Double.doubleToLongBits(tempValue);i = 0x5fe6ec85e7de30daL - (i >> 1);tempValue = Double.longBitsToDouble(i);tempValue = tempValue * (1.5d - xhalf * tempValue * tempValue);tempValue = this.value * tempValue;return tempValue;}

Comparsion:比较

笔者建立了一个专门的单元测试类来比较上述算法的准确度与性能,代码参考SquareRootsTest,首先在准确度与稳定性测试方面,这几种算法都能达到较好地稳定性,其中平方根倒数速算法相对而言是较好。


@Test
public void testBabylonian() {for (int i = 0; i < 10000; i++) {Assert.assertEquals(2.166795861438391, squareRoots.Babylonian(), 0.000001);}}@Test
public void testTSqrt() {for (int i = 0; i < 10000; i++) {Assert.assertEquals(2.166795861438391, squareRoots.TSqrt(), 0.000001);}
}@Test
public void testFastInverseSquareRoot() {for (int i = 0; i < 10000; i++) {Assert.assertEquals(2.1667948388864198, squareRoots.FastInverseSquareRoot(), 0.000001);}
}

而在性能测试方面,级数逼近的性能最差,巴比伦算法次之,平方根倒数速算法最好:


@Test
public void benchMark() {//巴比伦算法计时器long babylonianTimer = 0;//级数逼近算法计时器long tSqrtTimer = 0;//平方根倒数速算法计时器long fastInverseSquareRootTimer = 0;//随机数生成器Random r = new Random();for (int i = 0; i < 100000; i++) {double value = r.nextDouble() * 1000;SquareRoots squareRoots = new SquareRoots(value);long start, stop;start = System.currentTimeMillis();squareRoots.Babylonian();babylonianTimer += (System.currentTimeMillis() - start);start = System.currentTimeMillis();squareRoots.TSqrt();tSqrtTimer += (System.currentTimeMillis() - start);start = System.currentTimeMillis();squareRoots.FastInverseSquareRoot();fastInverseSquareRootTimer += (System.currentTimeMillis() - start);}System.out.println("巴比伦算法:" + babylonianTimer);System.out.println("级数逼近算法:" + tSqrtTimer);System.out.println("平方根倒数速算法:" + fastInverseSquareRootTimer);}/**
结果为:
巴比伦算法:17
级数逼近算法:34
平方根倒数速算法:7
**/

常用的平方根算法详解与实现相关推荐

  1. python牛顿法计算平方根_常用的平方根算法详解与实现

    本文从属于笔者的数据结构与算法系列文章. SquareRoot 平方根计算一直是计算系统的常用算法,本文列举出几张简单易懂的平方根算法讲解与实现.其中Java版本的代码参考这里 Reference B ...

  2. 常用AF对焦算法详解

    常用的AF算法框架 module 由module分别输出两个通道给到AP, 分别传输PDBuffer与RawBuffer:然后由算法针对拿到的Buffer进行计算,输出对应的CAF与PD结果: TOF ...

  3. 机器学习、深度学习中常用的优化算法详解——梯度下降法、牛顿法、共轭梯度法

    一.梯度下降法 1.总述: 在机器学习中,基于基本的梯度下降法发展了三种梯度下降方法,分别为随机梯度下降法,批量梯度下降法以及小批量梯度下降法. (1)批量梯度下降法(Batch Gradient D ...

  4. html5 游戏 算法,JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【圆形情况】...

    JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解[圆形情况] 发布时间:2020-10-10 13:42:43 来源:脚本之家 阅读:95 作者:krapnik 本文实例讲述了JS/HTML ...

  5. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

  6. FloodFill算法详解及应用

    FloodFill算法详解及应用 啥是 FloodFill 算法呢, 最直接的一个应用就是「颜色填充」,就是 Windows 绘画本中那个小油漆桶的标志,可以把一块被圈起来的区域全部染色. 这种算法思 ...

  7. YOLOv5算法详解

    目录 1.需求解读 2.YOLOv5算法简介 3.YOLOv5算法详解 3.1 YOLOv5网络架构 3.2 YOLOv5实现细节详解 3.2.1 YOLOv5基础组件 3.2.2 输入端细节详解 3 ...

  8. SoftPool算法详解

    Refining activation downsampling with SoftPool-论文链接-代码链接 目录 1.需求解读 2.SoftPool算法简介 3.SoftPool算法详解 3.1 ...

  9. md5与des算法有何不同_Python算法详解:为什么说算法是程序的灵魂?

    算法是程序的灵魂,只有掌握了算法,才能轻松地驾驭程序开发.软件开发工作不是按部就班,而是选择一种最合理的算法去实现项目功能.算法能够引导开发者在面对一个项目功能时用什么思路去实现,有了这个思路后,编程 ...

最新文章

  1. TCP 和 UDP的理解
  2. linux at自动挂化,linux的at定时任务的使用
  3. Shark集群搭建配置
  4. 机器学习-算法背后的理论与优化(part2)--广义线性模型
  5. linux实验三makefile,实验平台上Makefile详细的解释
  6. python按行读取文件取消空白行_python去掉空白行的多种实现代码
  7. 24种常用HTML常用实例
  8. b+树时间复杂度_几分钟学会Java实现图的最小生成树:Kruskal算法
  9. 三星+t800+原生android,三星T800(GALAXY Tab S WLAN版)一键救砖教程,轻松刷回官方系统...
  10. 宝塔面板无法安装php,宝塔面板安装php失败
  11. Java private方法访问
  12. 【转载】NP完全问题——最小曼哈顿网络
  13. 福特汉姆大学计算机科学专业,福特汉姆大学计算机研究生
  14. 推荐一个免费服务器网站|亲测可用
  15. 计算机等级二级c语言英文,计算机等级考试二级C语言考试大纲(国外英文资料).doc...
  16. 究竟是什么人在买爱马仕?
  17. 贝叶斯公式的理解及简单推导
  18. 使用x-switch进行代理
  19. 数据结构——图的数组(邻接矩阵)表示法
  20. Android 系统语言切换监听和设置

热门文章

  1. 绝地求生大逃杀地图分析
  2. 向暴雪(BLIZZARD)学什么
  3. 在单点登录中,如果 cookie 被禁用了怎么办
  4. 人脸活体检测:活体检测数据集
  5. 报表中小计汇总总计在代码实现
  6. HTTP首部字段脑图
  7. 每一个互联网公司都要掌握的《计算广告》,它是数据与计算的灵魂
  8. php系统性能分析论文,系统性能分析-PHP/Linux@HeFei-51CTO博客
  9. 自适应设计和响应式设计
  10. Go Slice实现原理分析