惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
美团技术团队
H
Hacker News: Front Page
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tenable Blog
Simon Willison's Weblog
Simon Willison's Weblog
T
The Exploit Database - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
C
CXSECURITY Database RSS Feed - CXSecurity.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
About on SuperTechFans
F
Fortinet All Blogs
量子位
GbyAI
GbyAI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
AWS News Blog
AWS News Blog
Forbes - Security
Forbes - Security
Help Net Security
Help Net Security
I
InfoQ
有赞技术团队
有赞技术团队
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
C
Check Point Blog
T
Troy Hunt's Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Latest news
Latest news
P
Proofpoint News Feed
Jina AI
Jina AI
Last Week in AI
Last Week in AI
Martin Fowler
Martin Fowler
雷峰网
雷峰网
博客园 - Franky
L
LangChain Blog
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
D
Docker
G
GRAHAM CLULEY
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

MoonLab

VSCode + OpenOCD 远程调试开发STM32 Clangd + VSCode使用方法 Keil5 编译错误 error: call to undeclared function '__enable_irq' BTSNOOP is FUN! 算法 - 前缀和 2025蓝桥杯赛后总结 三星ZFold 3改造 JavaScript 逆向 Steam 登录二维码 Protobuf Android设备安装Debian成为BT下载服务器 [双系统] Windows 更新摧毁了我的Linux系统 Reading List Golang embed 使用问题 Hexo博客自动备份插件 云盘备份支持 通过汇编分析栈、函数调用 esp&ebp Git push 出现 permisson denied error 403 坑:Litepal save方法返回true却没有保存 Android Shizuku源码分析 第二篇 Android Shizuku源码分析 Android 监听第三方Activity的一举一动 Android笔记#1 View的事件分发机制解析 知乎日报的问题 使用Hexo Hello World Ubnutu 无法启动网易云音乐 - 总结 Windows 好软推荐 | 这一定是良心软件 typecho - http转https 如何评价Android P MoonLab MoonLab MoonLab 关于 项目
快速求解平方根倒数算法
LingC · 2025-02-04 · via MoonLab

📦 由AI生成的摘要
本文介绍了一种快速计算平方根倒数的算法,该算法源于上世纪90年代。文章首先解释了浮点数在计算机中的存储方式,特别是float32格式的结构,包括符号位、指数位和尾数位。接着,介绍了牛顿迭代法的基本原理及其在求解平方根倒数中的应用。通过对浮点数的对数变换,推导出与平方根倒数相关的公式,并解释了代码中使用的神秘常数 0x5f3759df 的来源,最后提到切比雪夫最佳逼近的概念,以优化计算结果。

对于快速计算出平方根倒数 $\frac{1}{\sqrt{x}}$,有一个上世纪90年代的经典算法:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

扫盲:浮点数在计算机中的储存

float32和double64都由 IEE754 标准定义,在这里只简单了解float32。

float

在这32位中分为三个部分:

  • Sign 符号:0代表整数,1代表负数
  • Exponent 指数位

二进制的8bit可以表示256种状态,而IEE754规定,这八位用于表示[-127, 127]范围内的指数。 为了方便地表示负数,其规定在float32中指数的偏移量为127,因此指数的实际值为e = exponent - 127。 这将确保以二进制储存的biased exponent总是非负整数。

  • Fraction 尾数位

尾数位在格式中有23位,因此可以表示的精度为2^-23,约等于1.19 * 10^-7

如有一个十进制数13.62,将整数部分除2取余逆序排列为1101,将小数部分乘2取整顺序排列为101。这个十进制小数在二进制的表示为1101.101,即1.101101 * 2^3

将指数部分加上偏移量127,得到130,则exponent部分的值为10000010

因为规定了小数的最高位总是非零数,所以在二进制中它总是为1,因此在尾数部分可以省略最高位的储存,只考虑小数点后面的数字。如凑不够23位则低位补零。

$$ {\text{value}}=(-1)^{\text{sign}}\times 2^{(E-127)}\times \left(1+\frac{M}{2^{23}}\right) $$

其中,$\frac{M}{2^{23}}$ 将尾数 $M$ 归一化到范围 $[0, 1)$。

牛顿迭代法求根

对于 $ f(x)=0 $ 有一个近似解 $ x_n $,通过给出的根得到更近似的根。

$$ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} $$

NewtonMethod

已经证明牛顿迭代法的二次收敛条件: ${\displaystyle f'(x)\neq 0}$ ; ${\displaystyle x\in I}$,其中 ${\displaystyle I}$ 为区间$[α − r, α + r]$ ; ${\displaystyle f(x)}$ 在 ${\displaystyle I}$ 上连续可微; 初始根 $x_0$ 足够接近根 $x_*$

最开始的浮点数公式: $x=\left(1+\frac{M}{2^{23}}\right) 2^{(E-127)}$

两边同取对数,

$$ \begin{align} \log_{2}(x) &= \log_{2}(\left(1+\frac{M}{2^{23}}\right) 2^{(E-127)}) \\ &= \left(E-127\right)+\log_{2}(1+\frac{M}{2^{23}}) \end{align} $$

在$ x \in [0, 1]$,$\log_{2}(1+x) \approx x$,$ y=\log_{2}(1+x) $ 与 $y=x$ 在图像上十分接近。

$$ \begin{align} \log_{2}(x) &= \left(E-127\right)+\log_{2}(1+\frac{M}{2^{23}})\\ &= \frac{M}{2^{23}}+E-127 \\ &= \frac{M+2^{23} \times E}{2^{23}}-127 \end{align} $$

此时,$M+2^{23}E$ 就是浮点数在二进制中的表达,其中 $2^{23}$ 使 $E$ 在二进制中向左移23位。

$log_{2}(x) = \frac{M+2^{23} \times E}{2^{23}}-127 $ 其实就是浮点数 $x$ 与其在二进制中的关系

设有解 $a=\frac{1}{\sqrt{y}}$

$\log_{2}(a) = \log_{2}(\frac{1}{\sqrt{y}}) = -\frac{1}{2}\log_{2}(y)$

将浮点数 $a$ 和 $y$ 转化为二进制形式 $A, Y$,代入上式,得到

$\frac{A}{2^{23}}-127 = -\frac{1}{2}\left( \frac{Y}{2^{23}}-127 \right) $

$A = 381 \times 2^{22} + α - \frac{1}{2}Y$

这个式子,其实就是这行代码的含义:

i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 

0x5f3759df 这个值是怎么来的呢?或句话说,如何计算出最佳的修正因子$α$?

引入一个修正因子$α$,使得直线 $y=x$ 上移与 $y=\log_{2}(1+x)$ 在图像上更加接近。

$$\log_{2}(1+x) \approx x+α$$

切比雪夫最佳逼近

$$ E(\alpha) = \max_{x \in [0,b]} \left| (x + \alpha) - \log_2(1 + x) \right| $$

最佳逼近直线为

$$y=x+0.0431$$


Refs

float32 Picture (By Fresheneesz at the English Wikipedia project, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=3357169)

NewtonMethod Picture 作者 Ralf Pfeifer - de:Image:NewtonIteration Ani.gif,CC BY-SA 3.0,https://commons.wikimedia.org/w/index.php?curid=2268473