常用的平方根算法详解与实现
本文从属于笔者的数据结构与算法系列文章。
SquareRoot
平方根计算一直是计算系统的常用算法,本文列举出几张简单易懂的平方根算法讲解与实现。其中Java版本的代码参考这里
Reference
计算平方根的算法
Wiki-Methods of computing square roots
Babylonian:巴比伦算法/牛顿法
巴比伦算法可能算是最早的用于计算$sqrt{S}$的算法之一,因为其可以用牛顿法导出,因此在很多地方也被成为牛顿法。其核心思想在于为了计算x
的平方根,可以从某个任意的猜测值g
开始计算。在真实的运算中,我们往往将g
直接设置为x
,不过也可以选择其他任何的正数值。那么其计算的迭代过程为:
1.如果猜测值g
已经足够接近于正确的平方根,算法结束,函数将g
作为结果返回。
2.如果猜测值g
不够精确,那么使用g
和x/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
**/
常用的平方根算法详解与实现相关推荐
- python牛顿法计算平方根_常用的平方根算法详解与实现
本文从属于笔者的数据结构与算法系列文章. SquareRoot 平方根计算一直是计算系统的常用算法,本文列举出几张简单易懂的平方根算法讲解与实现.其中Java版本的代码参考这里 Reference B ...
- 常用AF对焦算法详解
常用的AF算法框架 module 由module分别输出两个通道给到AP, 分别传输PDBuffer与RawBuffer:然后由算法针对拿到的Buffer进行计算,输出对应的CAF与PD结果: TOF ...
- 机器学习、深度学习中常用的优化算法详解——梯度下降法、牛顿法、共轭梯度法
一.梯度下降法 1.总述: 在机器学习中,基于基本的梯度下降法发展了三种梯度下降方法,分别为随机梯度下降法,批量梯度下降法以及小批量梯度下降法. (1)批量梯度下降法(Batch Gradient D ...
- html5 游戏 算法,JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【圆形情况】...
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解[圆形情况] 发布时间:2020-10-10 13:42:43 来源:脚本之家 阅读:95 作者:krapnik 本文实例讲述了JS/HTML ...
- C++中的STL算法详解
1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...
- FloodFill算法详解及应用
FloodFill算法详解及应用 啥是 FloodFill 算法呢, 最直接的一个应用就是「颜色填充」,就是 Windows 绘画本中那个小油漆桶的标志,可以把一块被圈起来的区域全部染色. 这种算法思 ...
- YOLOv5算法详解
目录 1.需求解读 2.YOLOv5算法简介 3.YOLOv5算法详解 3.1 YOLOv5网络架构 3.2 YOLOv5实现细节详解 3.2.1 YOLOv5基础组件 3.2.2 输入端细节详解 3 ...
- SoftPool算法详解
Refining activation downsampling with SoftPool-论文链接-代码链接 目录 1.需求解读 2.SoftPool算法简介 3.SoftPool算法详解 3.1 ...
- md5与des算法有何不同_Python算法详解:为什么说算法是程序的灵魂?
算法是程序的灵魂,只有掌握了算法,才能轻松地驾驭程序开发.软件开发工作不是按部就班,而是选择一种最合理的算法去实现项目功能.算法能够引导开发者在面对一个项目功能时用什么思路去实现,有了这个思路后,编程 ...
最新文章
- TCP 和 UDP的理解
- linux at自动挂化,linux的at定时任务的使用
- Shark集群搭建配置
- 机器学习-算法背后的理论与优化(part2)--广义线性模型
- linux实验三makefile,实验平台上Makefile详细的解释
- python按行读取文件取消空白行_python去掉空白行的多种实现代码
- 24种常用HTML常用实例
- b+树时间复杂度_几分钟学会Java实现图的最小生成树:Kruskal算法
- 三星+t800+原生android,三星T800(GALAXY Tab S WLAN版)一键救砖教程,轻松刷回官方系统...
- 宝塔面板无法安装php,宝塔面板安装php失败
- Java private方法访问
- 【转载】NP完全问题——最小曼哈顿网络
- 福特汉姆大学计算机科学专业,福特汉姆大学计算机研究生
- 推荐一个免费服务器网站|亲测可用
- 计算机等级二级c语言英文,计算机等级考试二级C语言考试大纲(国外英文资料).doc...
- 究竟是什么人在买爱马仕?
- 贝叶斯公式的理解及简单推导
- 使用x-switch进行代理
- 数据结构——图的数组(邻接矩阵)表示法
- Android 系统语言切换监听和设置