开根号研究

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

开根号研究


List

Knowledge

1 sqrt函数

#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
int main(){
    double a;
    scanf("%lf",&a);
    printf("%.3lf",sqrt(a));
    return 0;
}

底层实现:ai+1 = ( ai + number/ai ) / 2

double my_sqrt(double number) {
    double new_guess,last_guess;
    if (number < 0) {
        printf("Cannot compute the square root of a negative number!\n");
        return -1;
    }
    new_guess = 1;
    do {
        last_guess = new_guess;
        new_guess = (last_guess + number / last_guess) / 2;
        printf("%.15e\n", new_guess);
    } while (new_guess != last_guess);
    return new_guess;
}

2 古老的中国技术

这是我的过程

这个方法平常数学考试也可以用qaq,这是小学奥数我爸传承的,中华文化博大精深,先祖的方法都是各种经验,虽然和国外的理论有差距,但也是智慧的结晶,要好好保存传承。

3 二分法

这不是数学课(函数)上学的吗
在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数;如果小了,就再拿右区间的中间数来试。比如求sqrt(16)的结果,你先试(0+16)/2=8,8*8=64,64比16大,然后就向左移,试(0+8)/2=4,4*4=16刚好,你得到了正确的结果sqrt(16)=4。
code
看一下与系统函数比较
compare
从图中可以看出,二分法和系统的方法结果上完全相同,但是性能上整整差了几百倍。为什么会有这么大的区别呢?难道系统有什么更好的办法?难道。。。。哦,对了,回忆下我们曾经的高数课,曾经老师教过我们“牛顿迭代法快速寻找平方根”,或者这种方法可以帮助我们。

4 牛顿迭代法

求出根号a的近似值:首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了。
例如,我想求根号2等于多少。假如我猜测的结果为4,虽然错的离谱,但你可以看到使用牛顿迭代法后这个值很快就趋近于根号2了:
( 4 + 2/4 ) / 2 = 2.25
( 2.25 + 2/2.25 ) / 2 = 1.56944..
( 1.56944..+ 2/1.56944..) / 2 = 1.42189..
( 1.42189..+ 2/1.42189..) / 2 = 1.41423..
….
bi
这种算法的原理很简单,我们仅仅是不断用(x,f(x))的切线来逼近方程x^2-a=0的根。根号a实际上就是x^2-a=0的一个正实根,这个函数的导数是2x。也就是说,函数上任一点(x,f(x))处的切线斜率是2x。那么,x-f(x)/(2x)就是一个比x更接近的近似值。代入 f(x)=x^2-a得到x-(x^2-a)/(2x),也就是(x+a/x)/2。
牛顿迭代法
然后我们再来看下性能测试:(Wa!)
性能比较

5 O(1)的神奇方法

这个是有故事的。一天上课(数学),我问光勋,你怎么求Sqrt,O(〖log〗_2 (n)啊!我say:哈哈,垃圾!(当然我想到的是那个神奇的我爸教我的方法O(〖log〗_10 (n)))
直到有一天,光勋没开,兴高采烈跑过来说:YJP,我会O(1)求根号了!我一脸懵逼……

float Xsqrt(float x){//必须是float double→0
    float hf=0.5*x;
    int i=*(int*)&x;
    i=0x5f375a86-(i>>1);
    x=*(float*)&i;
    x=x*(1.5-hf*x*x);
    x=x*(1.5-hf*x*x);
    x=x*(1.5-hf*x*x);
    return 1/x;
}

创造背景
Quake-III Arena (雷神之锤3)是90年代的经典游戏之一。该系列的游戏不但画面和内容不错,而且即使计算机配置低,也能极其流畅地运行。这要归功于它3D引擎的开发者约翰-卡马克(John Carmack)。事实上早在90年代初DOS时代,只要能在PC上搞个小动画都能让人惊叹一番的时候,John Carmack就推出了石破天惊的Castle Wolfstein, 然后再接再励,doom, doomII, Quake…每次都把3-D技术推到极致。他的3D引擎代码资极度高效,几乎是在压榨PC机的每条运算指令。当初MS的Direct3D也得听取他的意见,修改了不少API。
最近,QUAKE的开发商ID SOFTWARE 遵守GPL协议,公开了QUAKE-III的原代码,让世人有幸目睹Carmack传奇的3D引擎的原码。这是QUAKE-III原代码的下载地址:QUAKE-III原代码
我们知道,越底层的函数,调用越频繁。3D引擎归根到底还是数学运算。那么找到最底层的数学运算函数(在game/code/q_math.c), 必然是精心编写的。里面有很多有趣的函数,很多都令人惊奇,估计我们几年时间都学不完。在game/code/q_math.c里发现了这样一段代码。它的作用是将一个数开平方并取倒,经测试这段代码比(float)(1.0/sqrt(x))快4倍:
code
来看性能
compare
函数返回1/sqrt(x),这个函数在图像处理中比sqrt(x)更有用。
注意到这个函数只用了一次叠代!(其实就是根本没用叠代,直接运算)。编译,实验,这个函数不仅工作的很好,而且比标准的sqrt()函数快4倍!要知道,编译器自带的函数,可是经过严格仔细的汇编优化的啊!这个简洁的函数,最核心,也是最让人费解的,就是标注了“what the fuck?”的一句
i = 0x5f3759df – ( i >> 1 );
再加上y = y * ( threehalfs – ( x2 * y * y ) );
两句话就完成了开方运算!而且注意到,核心那句是定点移位运算,速度极快!特别在很多没有乘法指令的RISC结构CPU上,这样做是极其高效的。
算法的原理其实不复杂,就是牛顿迭代法,用x-f(x)/f’(x)来不断的逼近f(x)=a的根。
没错,一般的求平方根都是这么循环迭代算的但是卡马克(quake3作者)真正牛B的地方是他选择了一个神秘的常数0x5f3759df 来计算那个猜测值,就是我们加注释的那一行,那一行算出的值非常接近1/sqrt(n),这样我们只需要2次牛顿迭代就可以达到我们所需要的精度。好吧如果这个还不算NB,接着看:
普渡大学的数学家Chris Lomont看了以后觉得有趣,决定要研究一下卡马克弄出来的这个猜测值有什么奥秘。Lomont也是个牛人,在精心研究之后从理论上也推导出一个最佳猜测值,和卡马克的数字非常接近, 0x5f37642f。卡马克真牛,他是外星人吗?
传奇并没有在这里结束。Lomont计算出结果以后非常满意,于是拿自己计算出的起始值和卡马克的神秘数字做比赛,看看谁的数字能够更快更精确的求得平方根。结果是卡马克赢了… 谁也不知道卡马克是怎么找到这个数字的。
最后Lomont怒了,采用暴力方法一个数字一个数字试过来,终于找到一个比卡马克数字要好上那么一丁点的数字,虽然实际上这两个数字所产生的结果非常近似,这个暴力得出的数字是0x5f375a86。
Lomont为此写下一篇论文,”Fast Inverse Square Root”。
position Lomontの论文
最后,给出最精简的1/sqrt()函数:
这里写图片描述
大家可以尝试在PC机、51、AVR、430、ARM、上面编译并实验,惊讶一下它的工作效率。前两天有一则新闻,大意是说 Ryszard Sommefeldt 很久以前看到这么样的一段 code (可能出自 Quake III 的 source code):
这里写图片描述
他一看之下惊为天人,想要拜见这位前辈高人,但是一路追寻下去却一直找不到人;同时间也有其他人在找,虽然也没找到出处,但是 Chris Lomont 写了一篇论文 (in PDF) 解析这段 code 的算法 (用的是 Newton’s Method,牛顿法;比较重要的是后半段讲到怎么找出神奇的 0x5f3759df 的)。
PS1. 这个 function 之所以重要,是因为求 开根号倒数 这个动作在 3D 运算 (向量运算的部份) 里面常常会用到,如果你用最原始的 sqrt() 然后再倒数的话,速度比上面的这个版本大概慢了四倍吧… XD
PS2. 在他们追寻的过程中,有人提到一份叫做 MIT HACKMEM 的文件,这是 1970 年代的 MIT 强者们做的一些笔记 (hack memo),大部份是 algorithm,有些 code 是 PDP-10 asm 写的,另外有少数是 C code (有人整理了一份列表)

参考文献

鸣谢

光勋 帝都码农

平方根倒数速算法 在电影《微微一笑很倾城》中,肖奈大神在玻璃上写了一堆公式,提到平方根倒数速算算法,这个到底是一个什么算法?笔者看电影的时候打手机学了一下,发现该算法的作者真乃神人!今天有空,就把该算法写一写。在3D图形编程中,经常要求平方根的倒数,即1/Sqrt(x),如果用一般的代码(float)(1.0/sqrt(x)),,精度高,但是非常慢;我们需要一个快速,而又足够高精度的算法;著名游戏《雷神之锤III... 阅读详情

相关推荐

根号的几种算法实现

本代码实现了多种根号算法,方便大家对比。

shell计算变量的平方根

可以使用awk命令或者bc命令,有的系统上不一定有bc命令,可以用awk计算,下边的四条命令,1 2是等价的,3 4也是等价的 此外:用awk和bc命令做浮点计算是shell中常用的 #!/bin/bash a=143 b=$(awk -v x=$a &amp;amp;quot;BEGIN{print sqrt(x)}&amp;amp;quot;) echo $b b=$(echo &amp;amp;quot;$a&amp;amp;quot; | awk '{print sq

caixiong的博客 7139

一篇文章将三极管讲透:三极管从原理到应用,从参数到特性,从入门到精通

晶体三极管(Transistor)是一种半导体电子器件,也是电子工程中最基本的元件之一。它有三个区域,分别是P型半导体,N型半导体和P型半导体,从而形成PNP型晶体三极管或者NPN型晶体三极管。

学习帮的博客 9万+

Shell——数学运算

Shell中的数学运算:let、 $(( ))、$[ ]、expr以及bc 的使用方法

王元笙 2205

chatgpt赋能python:Python根号代码,你需要了解的一切

sqrt(x)是Python中求根号的函数,其中x为待根号的数值。sqrt()函数是NumPy数学库中的函数,需要先引入NumPy库才能使用。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。🧡AI职场汇报智能办公文案写作效率提升教程 🧡专注于AI+职场+办公方向。下图是课程的整体大纲下图是。

tulingtest的博客 322

Bash shell 的算术运算有四种方式

No.1:使用 expr eg. r=`expr 4 + 5`      echo $r 注意: 4 + 5 表达式中运算符和操作数之间要有空格   #  终于找到原因了,给力啊! 此外,对于乘法运算符 * ,使用expr需要加上\进行转义 即 r=`expr 4 \* 5` 又及:expr表达式中没有乘幂**运算 No.2:使用 $(( )) eg. r=$(( 4 +

747

ios根号怎么打_ios计算器根号 苹果手机计算器怎么根号 详情介绍

几乎所有的智能手机都自带计算器功能,而苹果手机的计算器甚至可以支持根号。不太熟悉这项功能小伙伴可能不知道苹果手机计算器怎么根号,今天小编教你ios计算器根号方法。工具/材料苹果手机ios计算器根号 苹果手机计算器怎么根号01苹果手机自带计算器,如下图所示打计算器,已经卸载的也可以重新下载。02默认如下图所示,只能实现一些简单的计算。不要以为苹果手机只能计算加减乘除,其实不是这样,步骤3...

weixin_28811757的博客 4037

根号算法合集:多种算法实现与比较

根号算法合集:多种算法实现与比较 去发现同类优质源项目:https://gitcode.com/ 项目介绍 根号算法合集是一个源项目,它集合了多种根号算法的实现,目的是帮助发者深入理解不同算法的原理和效率。这个项目提供了一个学习和对比的平台,让用户可以通过实际代码来掌握各种算法的特点和应用。 项目技术分析 算法种类 该项目实现了以下几种常见的根号算法: 牛顿迭代法(Newton's...

gitblog_06773的博客 1000

根号算法合集

根号算法合集 去发现同类优质源项目:https://gitcode.com/ 在此仓库中,我们为您提供了多种根号算法的实现,旨在帮助您更深入地理解和对比不同算法的原理和效率。 资源概述 本代码库包含了以下几种常见的根号算法实现: 牛顿迭代法(Newton's Method) 二分查找法(Binary Search) 秦九韶算法(秦归一法) 迭代逼近法(Iteration Approach...

gitblog_06713的博客 416

python根号_python的根号

广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!语法以下是sqrt()方法的语法 -import mathmath.sqrt( x )python注意 -此函数不可直接访问,需要导入math模块,然后需要使用math静态对象调用此函数。 2,n次方利用pow(a, b)函数即可。 需要a的r次方则pow(a, 1.0r)......

weixin_39884872的博客 4762

根号的笔算算法图解_手工根号原理及其步骤

根号原理:这里以1156为例,1156是四位数,所以它的算术平方根的整数部分是两位数,且易观察出其中的十位数是3.于是问题的关键在于;怎样求出它的个位数a?为此,我们从a所满足的关系式来进行分析.根据两数和的平方公式,可以得到1156=(30+a)^2=30^2+2×30a+a^2,所以1156-302=2×30a+a^2,即256=(3×20+a)a,这就是说,a是这样一个正整数,它与3×20...

weixin_39687468的博客 1万+

计算机如何实现根号

今天看到一个问题:计算机如何实现根号? 如何求一个数字的算术平方根(又叫根号,或者方)? 大家普遍都是用计算器直接计算的,对于程序员来说,就是调用sqrt()方法。但是其内部又是怎么实现的呢?下面作了下总结。 方法一:迭代法 学过计算方法的应该都还有印象:一个函数 f(x) 在区间 [a,b] 上连续,且 f(x)=0 在 x∈[a,...

baningtao1470的博客 2450

均方误差要根号吗_如何口算根号

点击“蓝字”关注我们端午节,欣赏轻松的数学。 上次听到两人在争执谁的口算和笔算能力更好,他们当场出题比赛谁算得更快,以小数作为最终结果,谁知两人却都被正根号23所难住了,我暗暗在远处摇头,心想,正根号23不就是约等于240分之1151(4.79583)嘛。 我之所以能够口算根号,是利用了牛顿迭代法(Newton's method),它也被称为牛顿-拉弗森方法,是一种计...

weixin_42525178的博客 1025

手动算根号

这是数学专栏的第一篇文章,数学专栏会记录我对数学相关的心得。为什么数学专栏的名字叫 “数学之美” 呢?因为数学拥有逻辑自洽的美,反之,如果体会不到美,就会觉得很枯燥。这次要介绍的手动算根号就非常能体现数学之美。研究问题这次研究的问题是 “如何手动算根号”。我们都知道,平方很好算,但算根号很难。虽然算根号可以通过计算器按出来,但数学上也有优雅的方法快速得到算根号的近似值,掌握了手动算根号的原理,你可...

前端精读周刊 793

根号算法题库

前言根号算法博大精深,决定在此收集。 例题我博客基本都能找到。带根号算法分块算法一种是最普通的分块算法,把序列分块,然后可以解决区间问题。分块算法可以维护一些线段树维护不了的东西,例如单调队列等,线段树能维护的东西必须能够进行信息合并,而分块则不需要。不过,和线段树一样,分块需要支持类似标记合并的东西。 具体实现时,用belong[i]表示i所属块。对于修改操作,某一块全部要被修改,则更改它的信

不来也不去的一只失忆蝴蝶 3256
上一篇: Poj2960 S-Nim
下一篇: 曼哈顿距离最小生成树与莫队算法
YJP_2014
博客等级 码龄12年 5粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值