当前位置: 首页 > news >正文

快速求平方根

1. 前置知识

  • 建议首先阅读我的另外一篇文章《雷神之锤 III 竞技场》快速求平方根倒数的计算探究》。
  • 建议大家自己看过《雷神之锤 III 竞技场》快速求平方根倒数的计算探究》学会快速求平方根倒数算法后,不看我这篇文章,自己推导一篇快速求平方根的算法,这也是对自己是否彻底掌握的一个测试。
  • 本篇文章是《雷神之锤 III 竞技场》快速求平方根倒数的计算探究》基础上的继续推导,写出快速计算平方根的函数,要计算的公式如下:
    y = x y = x 1 2 y = \sqrt{x} \\ y = x^{\frac{1}{2}} y=x y=x21

2. 计算过程

2.1第一步:对等式两边同时取以2为底的对数

log ⁡ 2 ( y ) = log ⁡ 2 ( x 1 2 ) log ⁡ 2 ( y ) = 1 2 log ⁡ 2 ( x ) \log_2(y) = \log_2(x^{\frac{1}{2}}) \\ \log_2(y) = \frac12\log_2(x) log2(y)=log2(x21)log2(y)=21log2(x)

2.2 第二步:浮点数取log的整数表达形式

《IEEE754 -浮点数的表示》 提到浮点数的计算公式为: ( − 1 ) S ∗ ( 1 + F 2 23 ) ∗ 2 ( E − 127 ) (-1)^S*(1+\frac F{2^{23}})*2^{(E-127)} (1)S(1+223F)2(E127)

  • 不考虑符号位。对其取对数
    log ⁡ 2 ( ( 1 + F 2 23 ) ∗ 2 E − 127 ) \log_2\left(\left(1+\frac{\mathrm{F}}{2^{23}}\right)*2^{\mathrm{E}-127}\right) log2((1+223F)2E127)
    ≈ 1 2 23 ( F + 2 23 ∗ E ) + u − 127 \approx \frac{1}{2^{23}} (F +2^{23}*E)+u -127 2231(F+223E)+u127

2.3第三步:将 第二步 带入 第一步

  • 化简一下公式
    l o g 2 ( y ) = 1 2 log ⁡ 2 ( x ) 1 2 23 ( F y + 2 23 ∗ E y ) + μ − 127 = 1 2 ( 1 2 23 ( F x + 2 23 ∗ E x ) + μ − 127 ) − − − − − − ( F y + 2 23 ∗ E y ) = 1 2 ∗ 2 23 ( 127 − μ ) + 1 2 ( F x + 2 23 ∗ E x ) log_2(y) = \frac12\log_2(x) \\ \frac{1}{2^{23}}(\mathrm{F}_{y}+2^{23}*\mathrm{E}_{y})+\mu-127=\frac{1}{2}\left(\frac{1}{2^{23}}(\mathrm{F}_{x}+2^{23}*\mathrm{E}_{x})+\mu-127\right) \\ ------\\ (\mathrm{F}_y+2^{23}*\mathrm{E}_y)=\frac12*2^{23}(127-\mu)+\frac12(\mathrm{F}_x+2^{23}*\mathrm{E}_x) log2(y)=21log2(x)2231(Fy+223Ey)+μ127=21(2231(Fx+223Ex)+μ127)(Fy+223Ey)=21223(127μ)+21(Fx+223Ex)
  • 结果已经呼之欲出了,如下图所示,红框代表的是 y y y的二进制值, 蓝框代表的是 x x x的二进制值。
    在这里插入图片描述

y 二进制 = 1 2 ∗ 2 23 ( 127 − μ ) + 1 2 ( x 二进制 ) y_{二进制} = \frac12*2^{23}(127-\mu)+\frac12(x_{二进制}) y二进制=21223(127μ)+21(x二进制)

  • μ = 0.0450465679168701171875 μ =0.0450465679168701171875 μ=0.0450465679168701171875(这个数字是《雷神之锤 III 竞技场》快速求平方根倒数的计算探究》中所给出的魔数反推出来的),计算出 新的魔数
    y 二进制 = 0 x 1 f b d 1 d f 5 + 1 2 ( x 二进制 ) y_{二进制} = 0x1fbd1df5+\frac12(x_{二进制}) y二进制=0x1fbd1df5+21(x二进制)

3. 最后在使用牛顿迭代法再次逼近一次结果,提高精度

3.1 将 y = x y = \sqrt{x} y=x 变换为 f ( x ) = 0 f(x) = 0 f(x)=0的形式

  • 消除根号 y = x y 2 = x y = \sqrt{x} \\y^2 = x y=x y2=x
  • 整理一下,得到 f ( x ) = 0 f(x) = 0 f(x)=0 的形式: y 2 − x = 0 y^2 - x = 0 y2x=0
  • 带入牛顿迭代法的通用公式 f ( y ) = y 2 − x f ′ ( y ) = 2 y − − − − − − − − − − − y n + 1 = y n − f ( y n ) f ′ ( y n ) − − − − − − − − − − − y n + 1 = y n − y n 2 − x 2 y n − − − − − − − − − − − − − − − − − − − − − − − y n + 1 = 1 2 ( y n + x y n ) f(y) = y^2 - x\\f'(y) = 2y\\ -----------\\ y_{n+1}=y_n-\frac{f(y_n)}{f'(y_n)}\\ -----------\\ y_{n+1}=y_n-\frac{{y_n^2}-x}{2y_n} \\ -----------------------\\ y_{n+1}=\frac12\left(y_n+\frac x{y_n}\right) f(y)=y2xf(y)=2yyn+1=ynf(yn)f(yn)yn+1=yn2ynyn2xyn+1=21(yn+ynx)

4. 代码实现

float Q_sqrt(float number) {
    int i;
    float x, y;
    const float half = 0.5f;
    x = number;
    
    // 1. 位级黑魔法:生成初始近似值
    i = *(long*)&x;           // 将浮点位模式转为整数
    i = 0x1fbd1df5 + (i >> 1); // 魔法常数调整
    y = *(float*)&i;         // 转回浮点数
    
    // 2. 牛顿迭代法优化精度
    y = half * (y + x / y);  // 第一次迭代
    // y = half * (y + x / y);  // 可选:第二次迭代
    
    return y;
}
http://www.dtcms.com/a/109120.html

相关文章:

  • 【每日一个知识点】分布式数据湖与实时计算
  • Ubuntu上离线安装ELK(Elasticsearch、Logstash、Kibana)
  • Vulkan实例教程1 - Vulkan应用程序结构(附代码)
  • node ---- 解决错误【Error: error:0308010C:digital envelope routines::unsupported】
  • 第一部分 领域驱动设计的原则与实践
  • 10.多线程
  • 【C++】第八节—string类(上)——详解+代码示例
  • P4305 [JLOI2011] 不重复数字
  • 系统与网络安全------Windows系统安全(8)
  • 纯c++实现transformer 训练+推理
  • AI+自动化测试:如何让测试编写效率提升10倍?
  • torch 拆分子张量 分割张量
  • idea运行tomcat项目,很慢的问题
  • 我想尝试做一个钢铁侠反应堆
  • 人工智能与大模型的关系
  • Java学习总结-io流-练习案例
  • 4.3学习总结
  • umi框架开发移动端h5
  • 【MySQL】理解MySQL的双重缓冲机制:Buffer Pool与Redo Log的协同之道
  • C++数据类型(整型、浮点型、字符型、布尔型)
  • 办公设备管理系统(springboot+ssm+jsp+maven)
  • 面向教育领域的实时更新RAG系统:核心模块设计与技术选型实践指南
  • C++:算术运算符
  • 统计子矩阵
  • Parasoft C++Test软件单元测试_操作指南
  • 从内核到应用层:Linux缓冲机制与语言缓冲区的协同解析
  • 【MyBatis】深入解析 MyBatis XML 开发:增删改查操作和方法命名规范、@Param 重命名参数、XML 返回自增主键方法
  • ES中经纬度查询geo_point
  • 图像处理之Homography matrix(单应性矩阵)
  • 2025年4月3日(模数转换器)