快速平方根倒数算法深度理解

2023-05-16

快速平方根倒数算法深度理解

快速平方根倒数算法是什么?
简单来说这个算法避开了开方和除法运算快速实现了
y = 1 x y= \frac{1}{\sqrt x} y=x 1

快速平方根倒数算法首次出现是在著名的雷神之锤3的图形计算优化代码中
话不多说先上c代码
一.代码

小白的我以为这么写的:
float y = 1/sqrt(x);

开发游戏的大佬是这么写的:
float Q_rsqrt(float number)
{
	long i; 
	float x2,y;
	const float threehalfs = 1.5F;
	x2= number * 0.5F;
	y= number;
	i= * (long * ) &y;
	i= 0x5f3759df-(i>>1);
	y= * (float * ) &i;
	//上述代码给牛顿迭代法提供了一个较好的初始值
	y=y * (threehalfs - (x2*y*y)); //牛顿迭代一次   
	//y=y * (threehalfs - (x2*y*y))    可持续迭代
}

经大佬测试代码比(float)(1/sqrt(x))快4倍。

初步观看代码:
①定义了32位整型变量i
②定义了两个32位浮点数
③将1.5存入一个常量
④将形参number除2存入x2
⑤将形参number存入y

之后的四行代码乍一看???莫慌下面开始正文

二.理解算法前的知识铺垫
1.IEEE 754 (二进制浮点数算术标准)

32位分为三个部分:符号位 指数部分

①符号位:0为正数 1为负数

②8位指数部分:8位可以表示0到255所有的数字,但我们还需要得到负指数。
因此我们对0-255减去127就可以得到-127到128之间所有的整数。
举个例子如果指数部分我想要4
那这八位必须表示4+127=131 即10000011
这样通过移码我们可以将正负指数都变成0-255之间的整数
③23位尾数:利用23位我们可以表示0到2^23-1之间的整数
对于十进制科学计数法,尾数是1到10
对于二进制科学计数法,尾数是1-2
11000 = 1.1 ∗ 2 4 11000=1.1*{2}^{4} 11000=1.124
0.0101 = 1.01 ∗ 2 − 3 0.0101=1.01*{2}^{-3} 0.0101=1.0123
在科学计数法中,第一位按照定义不可以是0,对于二进制这个数只能是1。因此我们不存储这一位。

说了一堆理论的我们举一个例子看一下浮点数是怎么存储在计算机中的:
我们拿 8.25 举例子

Ⅰ.写成二进制:1000.01
Ⅱ.变成科学计数法: 1.00001 ∗ 2 3 = ( 1 + 0.00001 ) ∗ 2 3 1.00001 *{2^3}=(1 + 0.00001) * {2^3} 1.0000123=(1+0.00001)23
Ⅲ.解释
指数部分我们用 8bit 表示 3+127
3对应的就是2^3中的3
(1 + 0.00001):加号前面的1我们丢掉不存
对于0.00001中小数点后的数我们用23位尾数去存

罗嗦了这么久现在我们可以轻松理解以下内容:
对于一个浮点数x(十进制或者二进制)有:
x = ( − 1 ) s ∗ ( 1 + m ) ∗ 2 e x=(-1)^s*(1+m)*{2}^{e} x=(1)s(1+m)2e

对于下式 ( 1 + 0.00001 ) ∗ 2 3 (1 + 0.00001) * {2^3} (1+0.00001)23
m : 00001 m:00001 m:00001
e : 3 e:3 e:3
我们将存取之后的8位指数部分用E表示
将存取之后的23位尾数部分用M表示

E : 3 + 127 E:3+127 E:3+127
M : 00001 ⋯ ( 补 18 个 0 填 满 23 位 ) M:00001\cdots(补18个0填满23位) M:0000118023
我们可以得出E e和M m的关系式
E = e + 127 E=e+127 E=e+127
M = 2 23 ∗ m M={2}^{23}*m M=223m
三.数学推导
y = 1 x y= \frac{1}{\sqrt x} \quad y=x 1
取对数:
① log ⁡ 2 y = − 0.5 ∗ log ⁡ 2 ①\log_2 y=-0.5* \log_2 log2y=0.5log2
将y和x分别用二进制科学计数法表示:
② y = ( 1 + m y ) ∗ 2 e y ②y=(1+m_y)*{2}^{e_y} y=(1+my)2ey
③ x = ( 1 + m x ) ∗ 2 e x ③x=(1+m_x)*{2}^{e_x} x=(1+mx)2ex

联合上述三个式子化简:
l o g 2 ( 1 + m y ) + e y = − 0.5 ∗ ( l o g 2 ( 1 + m x ) + e x ) log_2 (1+m_y)+e_y=-0.5*(log_2(1+m_x)+e_x) log2(1+my)+ey=0.5(log2(1+mx)+ex)
通过一次线性近似:
m y + b + e y = − 0.5 ∗ ( m x + b + e x ) m_y+b+e_y=-0.5*(m_x+b+e_x) my+b+ey=0.5(mx+b+ex)
m y = M y 2 23 m_y= \frac{M_y}{{2}^{23}} \quad my=223My
m x = M x 2 23 m_x= \frac{M_x}{{2}^{23}} \quad mx=223Mx
E y = e y + 127 E_y=e_y+127 Ey=ey+127
E x = e x + 127 E_x=e_x+127 Ex=ex+127
上述五个式化简:
M y + 2 23 ∗ E y = 1.5 ∗ 2 23 ∗ ( 127 − b ) − 0.5 ∗ ( M x + 2 23 ∗ E x ) M_y+{2}^{23}*E_y=1.5*{2}^{23}*(127-b)-0.5*(M_x+{2}^{23}*E_x) My+223Ey=1.5223(127b)0.5(Mx+223Ex)

I y = M y + 2 23 ∗ E y I_y=M_y+{2}^{23}*E_y Iy=My+223Ey
I x = M x + 2 23 ∗ E x I_x=M_x+{2}^{23}*E_x Ix=Mx+223Ex
对于 1.5 ∗ 2 23 ∗ ( 127 − b ) 1.5*{2}^{23}*(127-b) 1.5223(127b)我们令其为K,可以知道通过调节b的大小就可以改变K的值

前辈们给出了当
b = 0.0450465 b=0.0450465 b=0.0450465时有K=
K = 0 x 5 f 3759 d f K=0x5f3759df K=0x5f3759df
这刚好对应代码中:

i= 0x5f3759df-(i>>1);

通过一系列不怎么复杂的数学推导我们究竟得到了什么?
我们知道了一个输出结果的整形和输入整形之间的关系,即:
I y = K − 0.5 ∗ I x I_y=K-0.5*I_x Iy=K0.5Ix
四.代码解释

long i; 
float x2,y;
const float threehalfs = 1.5F;
x2= number * 0.5F;
y= number;
i= * (long * ) &y;

我们将数字number存入y中准备对其进行位操作,但是众所周知浮点数没有位操作的语句。
但是长整型数可以进行位操作!

如果执行下面这一行代码:

i=long(y);
y=4.456时i=4

但是我们想要的是将y逐位转化成长整型,换句话说按照上面的代码我们改变了二进制逐位的值。
因此我们采取下面代码:

i= (long * ) &y;

这句话干了什么呢?

简单来说它转换了y对应的内存地址而不是y这个数字本身。
或者说这句话告诉cpu把y指向的内存数据当成长整形来读取

&y              取到浮点数y的地址
(long * ) &y    将该地址转化成长整型
*(long * ) &y    再取其值

6666指针确实是个神奇的东西,我们继续向下
通过这句话浮点数y的二进制表示存入到了i中。

i= 0x5f3759df-(i>>1);

这句的理解在第三大部分可以轻松找到。
简单来说我们通过放缩系数和平移操作代替了除法和开方的过程,这大大提高了代码运行效率。

y = * (float *) &i;

和①类似我们再次通过这种操作将二进制位转换成浮点数。

通过上述三步我们得到了一个近似值。因此我们还需要进行牛顿迭代法继续使结果精确。

y=y * (threehalfs - (x2*y*y)); 

下面进行牛顿迭代法的数学推导:
y = 1 x y= \frac{1}{\sqrt x} y=x 1
f ( y ) = 1 y 2 − x f(y)=\frac{1}{y^2}-x f(y)=y21x
y n + 1 = y n − 1 y n 2 − x − 2 y n 3 = y n ∗ ( 3 2 − 1 2 ∗ x ∗ y n 2 ) y_{n+1}=y_n-\frac{\frac{1}{y_n^2}-x}{\frac{-2}{y_n^3}}=y_n*(\frac{3}{2}-\frac{1}{2}*x*y_n^2) yn+1=ynyn32yn21x=yn(2321xyn2)

五.总结
短短的几行代码背后是强大的数学支撑,万万想不到之前学过的高数会在算法中这样体现。
第一次试写涉及到数学公式推导的文章,如有疑问请大家多多留言!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

快速平方根倒数算法深度理解 的相关文章

  • 使用putty软件通过SSH方式登录华为设备时出现“Signature from server‘s host key is invalid”错误的解决方法

    问题现象 使用putty软件 xff08 0 71及之后的版本 xff09 通过SSH方式登录时可能会出现 Signature from server s host key is invalid 错误提示 xff1a 解决方法 方法1 xf
  • diy 企业级路由器(route os )

    Mikrotik Router Os 来自拉托维亚 xff0c 一个不起眼的欧洲小国家 xff0c 但是它的功能却是很强大 今天我就用口碑比较好的 ROS2 9 6 版进行讲解了 主要功能 xff1a IP 路由 支持无线热区 PPPoE
  • 双系统Ubuntu 18.04 + ROS Melodic + openvins +VINS-mono + Realsense L515 环境配置

    Ubuntu 18 04 准备工作 电脑图标右键 管理 磁盘管理 xff0c 选择空闲空间的D或E盘右键 压缩卷 压缩102400 xff08 100G xff09 下载ubuntu 18 04 6 desktop amd64 iso ht
  • C++语法复习笔记-9.C++STl、Boost库、多线程编程(进行中)

    文章目录 1 STL1 概览2 容器2 1 序列式容器vector list deque初始化遍历 for each函数 2 2 适配器stack queue priority queue初始化访问方式 2 3 关联型容器map set插入
  • SSD与HDD如何混合组raid并永久挂载硬盘?

    前言 xff1a 服务器上同时装有SSD和HDD硬盘 xff0c 如果想把系统装在SSD上 xff0c HDD用来存数据 xff0c 那么服务器应该如何组raid xff1f 又如何设置HDD硬盘永久挂载 xff1f 下面将以装有1个SSD
  • Golang 报错 | 操作mysql提示busy buffer

    背景说明 在使用github com go sql driver mysql 驱动操作数据库 xff0c 获取信息时报错 代码块 span class token keyword func span span class token fun
  • Python | 打印进度条的三种方法

    不使用模块 xff0c 手动打印进度条 span class token keyword def span span class token function Run span span class token punctuation sp
  • Nginx配置禁止IP访问

    时间背景 使用Nginx代理服务 xff0c 请求先到前端的代理服务器 xff0c 然后由代理服务器的nginx转发请求到后端的服务器 开始默认没有对IP访问做限制 xff0c 现在要求禁止IP访问 xff0c 大概是一个这样的架构 xff
  • git如何使用tag

    简介 我们可以创建一个tag来指向软件开发中的一个关键时期 xff0c 比如版本号更新的时候可以建一个 v2 0 v3 1 之类的标签 xff0c 这样在以后回顾的时候会比较方便 tag的使用很简单 xff0c 主要操作有 xff1a 查看
  • linux服务器最大支持连接数

    当我们被问到一台linux服务器最多可以支持多少连接时 xff0c 很多人第一反应是65535个 xff0c 因为端口是65535个 xff0c 还有人说受到TCP连接里四元组的空间大小限制 xff0c 那么到底是多少 xff1f 首先解释
  • Linux提示空间已满,找不到大文件

    当我们发现磁盘快满了 xff0c 然后删除某些服务的日志文件 xff0c 删除后发现磁盘空间仍然被占用 xff0c 但我们使用 du sh 命令 xff0c 发现目录下没有大文件 xff0c 这时我们应该考虑 xff0c 删除日志文件时 x
  • passwd修改用户密码报错

    故障现象 xff1a 1 修改密码时报错 passwd Authentication token manipulation error 2 添加用户报错 xff1a unable to lock password file 分析问题 xff
  • /etc/bashrc、/etc/profile、.bashrc、.bash_profile这几个文件的关系是什么呢?

    我们平时在配置一些环境变量的时候 xff0c 经常会遇到这几个文件的修改 xff0c 有的文档是修改 etc bashrc xff0c 而有的文档则是要求修改 bashrc xff0c 那么这几个文件到底有什么关系呢 xff1f 首先说一下
  • RouterOS系统安装和简单配置

    1 安装RouterOS系统 VMware虚拟机 xff0c 新建一个其他系统的虚拟机 xff0c 类似安装Linux系统 xff0c 挂载系统镜像 xff0c 根据提示一步步完成安装 选择安装的功能包 选择安装的功能包后 xff0c pr
  • nginx-upload-module模块使用

    Nginx是没有该模块的 xff0c 需要重新编译Nginx xff0c 添加nginx upload module模块 下载nginx upload module模块 xff1a https github com fdintino ngi
  • SecureCRT Mac版安装并激活

    先下载SecureCRT和破解文件 默认下载到了当前用户的 下载 目录中 在 Finder 中 打开 scrt 7 3 0 657 osx x64 dmg 并将 SecureCRT复制到 应用程序 中 这时SecureCRT的路径是 App
  • Python 报错 | 导入celery模块报错

    环境 xff1a Python3 7 celery4 1 0 进入python交互环境 xff0c 导入celery模块正常 xff0c 引用Celery的方法报错 xff1a liangkai vm span class token pu
  • yy欢聚时代软件测试笔试题

    1 xff0c 10111001对应的八进制 xff0c 十六进制和十进制 2 xff0c 常见的数据库有那些 xff1f 3 xff0c 常见的协议有哪些 xff1f 4 xff0c 代码运行结果 xff0c c 43 43 题目 xff
  • linux之conntrack连接跟踪

    linux之conntrack连接跟踪 conntrack连接跟踪 连接跟踪 xff08 CONNTRACK xff09 xff0c 顾名思义 xff0c 就是跟踪并且记录连接状态 Linux为每一个经过网络堆栈的数据包 xff0c 生成一
  • mdk arm开启FPU报错问题

    问题描述 xff1a mdk使用arm complier v6 开启FPU报错问题 问题分析 xff1a 如果是使用arm v5版本编译器 xff0c 按照下述步骤进行配置 xff0c 然后编译是没有问题的 xff1a 在C C 43 43

随机推荐

  • linux之yum下载rpm包离线安装conntrack-tools

    如何下载rpm包 xff0c 进行离线安装 文章目录 前言一 yum下载rpm包离线安装方式方法一 使用yum 的 downloadonly 插件下载方法二 使用yumdownloader下载方法三 使用repotrack下载所有依赖 二
  • docker离线安装方法

    docker离线安装方法 下载地址 xff1a https download docker com linux static stable x86 64 参考文档 xff1a https docs docker com engine ins
  • Linux使用chrony让局域网内的服务器时间同步

    Linux使用chrony让局域网内的服务器时间同步 在生产环境经常会因为时间的问题出现过问题 xff0c 例如应用节点和数据存节点时间不一致 xff0c 造成检索不到数据的问题等 在现在不管是公有云 私有云还是混合云等在建设过程中 xff
  • linux将本地库JAR批量导入到Nexus3.x

    linux将本地库JAR批量导入到Nexus3 x 文章目录 linux将本地库JAR批量导入到Nexus3 x1 问题描述2 搭建Nexus私服2 1 官网下载 xff1a 2 2 上传并解压2 3 修改默认端口2 4 修改内存分配 xf
  • 如何下载npm离线安装包

    如何下载npm离线安装包 如何将本地nodejs库 xff0c 放入到nexus的npm库 在代码工程目录使用 npm install 安装 package json 所依赖的文件 xff0c 并依赖下载到 node modules 目录
  • 批量下载npm离线安装包

    批量下载npm离线安装包 上篇讲到如何下载npm离线安装包的几种思路 https blog csdn net xinle0320 article details 124285708 1 批量下载npm离线安装包 三种方式 通过 packag
  • Fiddler抓取Java应用HTTP请求报文

    Fiddler抓取Java应用HTTP请求报文 1 监听Tomcat的http请求报文 在catalina bat添加一行 xff08 proxyPort的值为fiddler端口号 xff09 span class token builti
  • NPM软件包发布到Nexus

    NPM软件包发布到Nexus 文章目录 1 Linux安装nodejs环境2 创建镜像仓库3 添加nexus权限4 设置镜像仓库地址5 发布单个包6 发布tgz包7 批量发布npm包到私有仓库8 查看nexus的npm仓库9 测试 1 Li
  • docker安装minio

    docker安装minio 1 拉取镜像2 查看镜像3 创建目录4 指定控制台端口启动4 查看日志5 登录控制台页面6 Create Bucket7 浏览文件 1 拉取镜像 span class token function docker
  • docker minio设置永久免密下载链接

    docker minio设置永久免密下载链接 上篇 docker安装minio 前言 minio分享文件的链接 xff0c 最多支持分享七天 通过minio client管理存储桶策略的方式实现文件链接永久有效 这样就可以免密搭建个人图片等
  • printf重定向的相关总结

    简介 实现printf重定向有多种方式 xff0c 下面一一介绍 linux环境下 虽然linux系统的默认标准输出设备是显示器 xff0c 但是我们可以把printf打印输出的内容重定向到其他设备或文件 方法如下 xff1a 方法1 xf
  • 安装ES7.x集群

    安装ES集群 文章目录 安装ES集群一 环境准备1 1 准备三台Linux主机1 2 ES集群环境规划1 3 修改 etc hosts 二 下载部署包2 1下载jdk部署包2 2下载ES相关部署包 三 环境安装3 1安装JDK8环境3 1
  • es7.x升级log4j版本

    es7 x升级log4j版本 下载log4j2 18 0 下载地址 xff1a https dlcdn apache org logging log4j 2 18 0 apache log4j 2 18 0 bin tar gz 其他版本
  • 使用logstash迁移ES1.x数据到ES7.x

    使用logstash迁移ES1 x数据到ES7 x tar span class token operator span zxvf logstash span class token operator span span class tok
  • ES创建索引模板设置分片和副本数及时间格式问题

    创建索引模板设置分片和副本及时间格式问题 一 创建索引模板 PUT template event template default span class token punctuation span span class token str
  • es7 扩展词库

    elasticsearch 7 x x 扩展ik分词词库 支持mysql 热部署 https blog csdn net laow1314 article details 124236262 Elasticsearch 7 X Ik源码解读
  • es相关参数优化

    es相关参数优化 生产环境 jvm参数资源可以调整大一些 xff0c 系统的内存的一半给ES服务 xff0c 最大不超过32G xff0c 剩下的资源留给底层Lucene缓冲 xff1b 独立部署ES服务 xff0c 可以使用64G内存的节
  • ROS中rqt_graph报错节点图空白问题

    ROS中rqt graph报错节点图空白问题 我的环境配置 xff1a 1 VM ware虚拟机安装的ubuntu系统20 04 2 ROS版本是noetic 问题如下 xff1a 最近在学习ROS过程中遇到了rqt graph报错的问题
  • ROS中Gazebo无响应解决办法

    标题ROS中Gazebo无响应解决办法 在终端输入gazebo没有反映 xff0c 进行下面两句操作 首先输入下面的代码 gazebo span class token operator span verbose 观察到报错显示原因为有另一
  • 快速平方根倒数算法深度理解

    快速平方根倒数算法深度理解 快速平方根倒数算法是什么 xff1f 简单来说这个算法避开了开方和除法运算快速实现了 y 61 1 x