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

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

SquareRoot

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

Reference

Babylonian:巴比伦算法/牛顿法

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

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

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

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

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

1460000006773717

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

public double Babylonian() {

double g = this.value;

while (isApproximate(g)) {

g = (g + this.value / g) / 2;

}

return g;

}

基于泰勒公式的级数逼近

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

1460000006122258

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

1460000006122261

根据该公式我们可以在一定精度内逼近真实值,不过这个公式仍然存在一个问题,即是公式的收敛问题。在泰勒级数展开中,平方根函数的公式当且仅当参数值位于一个有效范围内时才有效,在该范围内计算趋于收敛。该范围即是收敛半径,当我们对平方根函数用a=1进行计算时,泰勒级数公式希望x处于范围:$0

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

**/

1460000006122260

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/472860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql主辅同步报错_mysql数据库主辅同步Slave_IO_Running,Slave_SQL_Running错误

Slave_IO_Running&#xff1a;连接到主库&#xff0c;并读取主库的日志到本地&#xff0c;生成本地日志文件Slave_SQL_Running:读取本地日志文件&#xff0c;并执行日志里的SQL命令。这个错误是出现在我重启电脑之后。从以上图片来看&#xff0c;我遇到的错误是第二条&#xff…

R.java文件介绍

HelloWorld工程中的R.java文件 package com.android.hellworld; public final class R { public static final class attr { } public static final class drawable { public static final int icon0x7f020000; } public static final class layou…

移动计算比移动数据更划算

learn from 从0开始学大数据&#xff08;极客时间&#xff09; 数据太大&#xff08;PB级别&#xff09;&#xff0c;将程序发送到数据所在地方进行计算&#xff0c;比移动数据更划算 如何实现的&#xff1a; 将大规模数据存储在集群的所有服务器上&#xff0c;&#xff08;H…

什么是spring_Spring 源码第三弹!EntityResolver 是个什么鬼?

上篇文章和小伙伴们说了 Spring 源码中 XML 文件的解析流程&#xff0c;本来可以继续往下走看加载核心类了&#xff0c;但是松哥还是希望能够慢一点&#xff0c;既然要学就学懂&#xff0c;在 XML 文件解析的过程中还涉及到一些其他的类和概念&#xff0c;因此我就先用几篇文章…

mysql5.7免安版配置_mysql5.7免安装版配置

JS产生随机数的几个用法&#xff01;C&plus;&plus;和java多态的区别C和java多态的区别 分类: Java2015-06-04 21:38 2人阅读 评论(0) 收藏 举报 &#xfeff;&#xfeff; 转载自:http://www.cnblogs.com/plmnko/archive ...永远不要在Linux 执行的 10 个最危险的命令转…

简述C++程序编写的过程

学习C编程&#xff08;相关C编程-基础知识篇&#xff09;乃至于所有的编程语言每当你编写一个程序从编写到最后得到运行结果要经历以下一些步骤&#xff1a;1、用C语言编写程序用高级语言编写的程序称为“源程序”(source program)&#xff61;C的源程序是以.cpp作为后缀的(cpp…

从RAID看垂直伸缩到水平伸缩的演化

learn from 从0开始学大数据&#xff08;极客时间&#xff09; 大规模数据存储问题&#xff1a; 容量问题&#xff0c;数据量超过磁盘容量读写速度&#xff0c;磁盘读写慢数据可靠性&#xff0c;磁盘寿命问题 RAID&#xff08;独立磁盘冗余阵列&#xff09; 是将多块普通磁盘…

linux安装g++编译器_Ubuntu Desktop下配置Rosetta安装教程

作者: 吴炜坤本文仅在虚拟机环境下测试&#xff0c;可能实际操作中会遇到不同的问题本文是新手向的安装教程&#xff0c;如果需要在CentOS上安装&#xff0c;可以参考本人其他安装教程由于许多新人朋友在学习Rosetta过程中&#xff0c;通常操作系统选择的都是带美丽漂亮界面便于…

mysql+inser+select_解析MySQL中INSERT INTO SELECT的使用

1. 语法介绍有三张表a、b、c&#xff0c;现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段。对于这种情况&#xff0c;可以使用如下的语句来实现&#xff1a;INSERT INTO db1_name (field1,field2) SELECT field1,field2 FROM db2_name上面的语句比较适合两个表的…

HDFS依然是存储的王者

learn from 从0开始学大数据&#xff08;极客时间&#xff09; 1. HDFS 架构 DataNode 负责数据的存储、读写&#xff0c;HDFS 将文件分割成若干数据块&#xff08;Block&#xff09;&#xff0c;每个 DataNode 存储一部分数据块&#xff0c;文件就分布存储在整个 HDFS 服务器集…

DateTime和字符串转换问题

DateTime和string之间的相互转换经常碰到,可就这么简单的一个转换其中也有些需要注意的地方. 1 static void Main(string[] args)2 {3 string format "yyyy/MM/dd HH:mm:ss";4 DateTimeFormatInfo dtfi DateTimeFormatInf…

.net 5 正式版_.NET 5正式版快来了

微软已在5月19号发布了.NET 5.0的第四个预览版。什么是.NET 5.NET 5.0.NET 5.0是.NET Framework和.NET Core核心的结合&#xff0c;旨在统一.NET平台&#xff0c;微软将其描述为“.NET的未来”&#xff0c;正式版预计将于2020年11月10日发布。.NET 5.0的高级目标包括提供统一的…

mysql 身份证判断性别_sql根据身份证号判断所在地域、年龄、性别

应用场景使用有效身份证来判断用户的基本信息&#xff0c;所在地区、年龄、性别时候。sql语句&#xff1a;SELECTcase left(id_card,2)when 11 then 北京市when 12 then 天津市when 13 then 河北省when 14 then 山西省when 15 then 内蒙古自治区when 21 then 辽宁省when 22 the…

天池 在线编程 矩阵还原(前缀和)

文章目录1. 题目2. 解题1. 题目 输入: 2 2 [[1,3],[4,10]] 输出: [[1,2],[3,4]]Explanation: before: 1 2 3 4after: 1 3 4 10https://tianchi.aliyun.com/oj/286606814880453210/327250187142763355 2. 解题 前缀和逆运算 class Solution { public:/*** param n: the row o…

input 输入事件_输入超时为例学习 Python 的线程和协程

需求&#xff1a;做一个程序等待用户输入&#xff0c;3秒内输入则会 echo 这个输入并立即退出。3秒内没输入则自动退出。实现方法&#xff1a;1. 线程&#xff08;错误示范&#xff09;import 首先启动两个线程&#xff0c;并把等待输入的 get_input 设置成 daemon。于是 3 秒后…

PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询–合理利用算法,效率提高2125倍...

目前的工作是需要对用户的一些数据进行分析&#xff0c;每个用户都有若干条记录&#xff0c;每条记录中有用户的一个位置&#xff0c;是用经度和纬度表示的。 还有一个给定的数据库&#xff0c;存储的是一些已知地点以及他们的经纬度&#xff0c;内有43W多条的数据。 现在需要拿…

js固定表格行列_纯前端表格控件SpreadJS V14.0发布:组件化编辑器+数据透视表

SpreadJS 是一款基于 HTML5 的纯前端表格控件&#xff0c;兼容 450 种以上的 Excel 公式&#xff0c;具备“高性能、跨平台、与 Excel 高度兼容”的产品特性&#xff0c;可为用户提供高度类似 Excel 的功能&#xff0c;满足 Web Excel组件开发、 表格文档协同编辑、 数据填报、…

天池 在线编程 区间统计(队列)

文章目录1. 题目2. 解题1. 题目 给定一个01数组 arr 和 一个整数 k, 统计有多少区间符合如下条件: 区间的两个端点都为 0 (允许区间长度为1)区间内 1 的个数不多于 k arr 的大小不超过 10^5 样例 1: 输入: arr [0, 0, 1, 0, 1, 1, 0], k 1 输出: 7 解释: [0, 0], [1, 1],…

android 模糊查询控件_第三十二篇:在SOUI2.0中像android一样使用资源

SOUI2.0之前&#xff0c;在SOUI中使用资源通常是直接使用这个资源的name(一个字符串)来引用。使用字符串的好处在于字符串能够表达这个资源的意义&#xff0c;因此使用字符串也是现代UI引擎常用的方式。尽管直接使用字符串有意义明确的优点&#xff0c;它同样也有缺点&#xff…

采用java信号量(semaphore)让线程轮流打印

semaphore是java.util.concurrent包下的并发工具类。 A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially relea…