【学习笔记】使用魔数快速求平方根

简介

介绍使用魔数0x1fbd1df5快速求平方根x{\sqrt{x}}x​的C语言实现和公式的推导。

代码

float MagicSqrt(float x)
{float xhalf = 0.5f * x;int i = *(int*)&x;i = 0x1fbd1df5 + (i >> 1);x = *(float*)&i;x = 0.5f * x + xhalf / x;return x;
}

代码用于快速计算平方根x{\sqrt{x}}x​。

代码中核心部分是

i = 0x1fbd1df5 + (i >> 1);

该行代码就完成了计算平方根。

另外再使用一次牛顿迭代法提高下精度

x = 0.5f * x + xhalf / x;

所以整个计算过程就是

1.i = *(int*)&x;

将输入的数转换成整数

2.i = 0x1fbd1df5 + (i >> 1);

通过魔数完成平方根的计算。

3.x = *(float*)&i;

转换回浮点数。

4.x = 0.5f * x + xhalf / x;

使用一次牛顿迭代法提高下精度。

完成快速计算平方根x{\sqrt{x}}x​。

如果需要提高精度,可以多进行一次牛顿迭代。

float MagicSqrt(float x)
{float xhalf = 0.5f * x;int i = *(int*)&x;i = 0x1fbd1df5 + (i >> 1);x = *(float*)&i;x = 0.5f * x + xhalf / x;x = 0.5f * x + xhalf / x;return x;
}

传进来的值x必须大于或等于0。

可以加入一个判断防止传入的值小于0.

float MagicSqrt(float x)
{if (x < 0){return -1;}else{float xhalf = 0.5f * x;int i = *(int*)&x;i = 0x1fbd1df5 + (i >> 1);x = *(float*)&i;x = 0.5f * x + xhalf / x;//x = 0.5f * x + xhalf / x;return x;}
}

牛顿迭代法计算方式

一般计算平方根可以使用牛顿迭代法。

xn+1=xn−f(xn)f′(xn)x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}xn+1​=xn​−f′(xn​)f(xn​)​

我们计算平方根的公式:

y=x=x12y = {\sqrt{x}} = x^{\frac 12}y=x​=x21​

所以

y2=x{y}^2 = xy2=x

构建以y为自变量的函数方程为

f(y)=y2−x=0f(y) = {y}^2 - x = 0f(y)=y2−x=0

f′(y)=2y=0f'(y) = {2}{y} = 0f′(y)=2y=0

将f(y)f(y)f(y)和f′(y)f'(y)f′(y)带入

y−f(y)f′(y)=y−y2−x2yy - \frac{f(y)}{f'(y)} = y - \frac{{{y}^{2}} - x}{{2}{y}}y−f′(y)f(y)​=y−2yy2−x​

​ =12(y+xy)= \frac{1}{2}{(y + \frac{x}{y})}=21​(y+yx​)

所以

yn+1=12(yn+xyn)y_{n+1} = \frac{1}{2}{(y_{n} + \frac{x}{y_{n}})}yn+1​=21​(yn​+yn​x​) = 0.5yn+0.5x÷yn0.5{y_n} + 0.5{x}÷{y_n}0.5yn​+0.5x÷yn​

实际计算,设x=2x = 2x=2,y1=2y_1 = 2y1​=2

y2=0.5×2+0.5×2÷2=1.5y_2 = 0.5 × 2 + 0.5 × 2 ÷ 2 = 1.5y2​=0.5×2+0.5×2÷2=1.5

y3=0.5×1.5+0.5×2÷1.5=1.416667y_3 = 0.5 × 1.5 + 0.5 × 2 ÷ 1.5 = 1.416667y3​=0.5×1.5+0.5×2÷1.5=1.416667

y4=0.5×1.416667+0.5×2÷1.416667=1.414216y_4 = 0.5 × 1.416667 + 0.5 × 2 ÷ 1.416667 = 1.414216y4​=0.5×1.416667+0.5×2÷1.416667=1.414216

y5=0.5×414216+0.5×2÷414216=1.414214y_5 = 0.5 × 414216 + 0.5 × 2 ÷ 414216 = 1.414214y5​=0.5×414216+0.5×2÷414216=1.414214

经过多次迭代,计算出来的结果2≈1.414214{\sqrt{2}} \approx 1.4142142​≈1.414214。

使用牛顿迭代法计算平方根需要大量的浮点数运算,运算速度会远远弱于整数运算。

算法讲解

接下来解释该算法的核心i = 0x1fbd1df5 + (i >> 1);

首先需要知道浮点数的基本概念。

32位浮点数基本概念

浮点数由三部分组成:符号,指数和尾数。

32位浮点数,用二进制表示

用公式表示就是

(−1)s(1+m)2e(-1)^s(1+m)2^e(−1)s(1+m)2e

这里s是符号(sign),e是指数(exponent),m是尾数(mantissa)。

因为这里计算平方根只对正数有意义,所以从假设符号位是 0 ,公式简化为

(1+m)2e(1+m)2^e(1+m)2e

指数部分eee的数值范围,−127≤e≤128-127 \leq e \leq 128−127≤e≤128。

尾数部分mmm的数值范围,0≤m<10 \leq m < 10≤m<1。

如果将浮点数转换成整数时,整数的数值就是

M+LEM + LEM+LE

这里EEE表示指数(exponent),MMM表示尾数(mantissa),LLL是2232^{23}223。

将指数部分看做是整数,用EEE来表示,那么范围是0≤E≤2550 \leq E \leq 2550≤E≤255。EEE如果减去127,范围变成-127 - 128,变成一个有符号数。

所以EEE和eee的转换关系是e=E−Be = E - Be=E−B,BBB是127。

如果将尾数部分看做是整数,用MMM来表示。数值范围是0≤M<2230 \leq M < 2^{23}0≤M<223。

所以MMM和mmm的转换关系是m=MLm = \frac{M}{L}m=LM​,LLL是2232^{23}223。

推导过程

接下来进入推导过程。

给定一个xxx,计算平方根yyy:

y=x=x12y = {\sqrt{x}} = x^{\frac 12}y=x​=x21​

首先对等式两边取以 2 为底的对数

log⁡2y=12log⁡2x\log_2 y = {\frac 12}\log_2 xlog2​y=21​log2​x

将x和y用浮点数替换:

log⁡2((1+my)2ey)=12(log⁡2((1+mx)2ex))\log_2 ((1+m_y)2^{e_y}) = {\frac 12}(\log_2 ((1+m_x)2^{e_x}))log2​((1+my​)2ey​)=21​(log2​((1+mx​)2ex​))

log⁡2(1+my)+ey=12(log⁡2(1+mx)+ex)\log_2 (1+m_y) + e_y = {\frac 12}(\log_2 (1+m_x) + e_x)log2​(1+my​)+ey​=21​(log2​(1+mx​)+ex​)

算式两边都有这样的项

log⁡2(1+v)\log_2(1 + v)log2​(1+v)

其中v的值范围0 < vvv < 1。

当v的取值在0到1之间时,这个函数和一条直线很接近:

方程式:

log⁡2(1+v)≈v+σ\log_2(1 + v) \approx v + \sigmalog2​(1+v)≈v+σ

其中σ\sigmaσ是一个常数,可以通过调整这个常数让两个曲线更加近似。

上面的方程

log⁡2(1+my)+ey=12(log⁡2(1+mx)+ex)\log_2 (1+m_y) + e_y = {\frac 12}(\log_2 (1+m_x) + e_x)log2​(1+my​)+ey​=21​(log2​(1+mx​)+ex​)

进行化简

my+σ+ey≈12(mx+σ+ex)m_y + \sigma + e_y \approx {\frac 12}(m_x + \sigma + e_x)my​+σ+ey​≈21​(mx​+σ+ex​)

接下来用整形解释下的指数和尾数来替代浮点数解释:

MyL+σ+Ey−B≈12(MxL+σ+Ex−B)\frac{M_y}{L} + \sigma + E_y - B \approx {\frac 12}(\frac{M_x}{L} + \sigma + E_x - B)LMy​​+σ+Ey​−B≈21​(LMx​​+σ+Ex​−B)

进行化简

MyL+Ey≈12(MxL+σ+Ex−B)−σ+B\frac{M_y}{L} + E_y \approx {\frac 12}(\frac{M_x}{L} + \sigma + E_x - B) - \sigma + BLMy​​+Ey​≈21​(LMx​​+σ+Ex​−B)−σ+B

MyL+Ey≈12(MxL+Ex)−12(σ−B)\frac{M_y}{L} + E_y \approx {\frac 12}(\frac{M_x}{L} + E_x) - \frac{1}{2}(\sigma - B)LMy​​+Ey​≈21​(LMx​​+Ex​)−21​(σ−B)

My+LEy≈12L(B−σ)+12(Mx+LEx)M_y + LE_y \approx {\frac 12}L(B - \sigma) + {\frac 12}(M_x + LE_x)My​+LEy​≈21​L(B−σ)+21​(Mx​+LEx​)

两边都得到了整形解释的值:

Iy≈12L(B−σ)+12Ix\mathbf{I_y} \approx {\frac 12}L(B - \sigma) + {\frac 12}\mathbf{I_x}Iy​≈21​L(B−σ)+21​Ix​

其中12L(B−σ){\frac 12}L(B - \sigma)21​L(B−σ)是一个常数。

用代码表示就是:

i = K + (i >> 1);

K就是算法中的常数。通过选取合适的σ\sigmaσ的值,就能得到K值。

魔数的选定

计算魔数所用的​可以采用穷举搜索或者二分法寻找最优值。

这里选定的值为σ\sigmaσ = 0.0450465。

带入计算出K值:

K=12L(B−σ)=12223(127−0.0450465)≈532487669=0x1fbd1df5K = {\frac 12}L(B - \sigma) = {\frac 12}{2^{23}}(127 - 0.0450465) \approx 532487669 = 0x1fbd1df5K=21​L(B−σ)=21​223(127−0.0450465)≈532487669=0x1fbd1df5

这里的K值就是公式中的0x1fbd1df5。

参考资料

平方根倒数速算法
0x5f3759df


本文链接:https://blog.csdn.net/u012028275/article/details/113793827

【学习笔记】使用魔数快速求平方根相关推荐

  1. 【学习笔记】使用魔数快速求立方根

    [学习笔记]使用魔数快速求立方根 简介 介绍使用魔数0x2a517d47快速求立方根 x 3 {\sqrt[3]{x}} 3x ​的C语言实现和公式的推导. 代码 float MagicCubeRoo ...

  2. JDBC学习笔记01【JDBC快速入门、JDBC各个类详解、JDBC之CRUD练习】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  3. Redis学习笔记①基础篇_Redis快速入门

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 资料链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA( ...

  4. OGG学习笔记04-OGG复制部署快速参考

    OGG学习笔记04-OGG复制部署快速参考 源端:Oracle 10.2.0.5 RAC + ASM 节点1 Public IP地址:192.168.1.27 目标端:Oracle 10.2.0.5 ...

  5. Servlet和HTTP请求协议-学习笔记01【Servlet_快速入门-生命周期方法、Servlet_3.0注解配置、IDEA与tomcat相关配置】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

  6. Python学习笔记--10.Django框架快速入门之后台管理admin(书籍管理系统)

    Python学习笔记--10.Django框架快速入门之后台管理 一.Django框架介绍 二.创建第一个Django项目 三.应用的创建和使用 四.项目的数据库模型 ORM对象关系映射 sqlite ...

  7. UE4学习笔记1st:编程快速入门

    UE4学习笔记1st:编程快速入门 今天我开始学习虚幻4游戏引擎,为了此我专门买了新的电脑,我将主要配置写在这里,有想学习的同学可以参考 显卡:丽台K620 CPU:E3-1230-V3 主板:b85 ...

  8. matlab修改变量名称_MATLAB学习笔记1:如何快速创建多个仅有数字变化变量名?...

    一直以来,本人用MATLAB都是想用什么功能就搜索什么功能,或者查看MATLAB帮助文档.(不得不说MATLAB的帮助文档做得真好) 由于没有系统学习过MATLAB,所以代码都很水-- 好吧,开个文章 ...

  9. 视觉SLAM十四讲学习笔记-第四讲-李代数求导与扰动模型

    专栏系列文章如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习 ...

最新文章

  1. jgit查询远程仓库_JAVA 使用jgit管理git仓库
  2. 了解过去与理解现在的一把钥匙
  3. linux c 创建子进程执行任务 简介
  4. python 开发版-MicroPython开发之物联网快速开发板
  5. 5个经典的JavaScript面试题
  6. Yoga710笔记本Win10和Ubuntu系统共存
  7. python list是数组还是链表实现的_python 数据结构 list和链表实现栈的三种方法
  8. 信息学奥赛C++语言:判断奇偶
  9. 认识Linux系统中的inode,硬链接和软链接
  10. 90-40-009-源码-CUBE-引擎为Spark写入Hbase本
  11. mysql数据库自增字段_mysql 数据库自增字段
  12. Windows2003环境下的一键系统安全
  13. VS2010/MFC编程入门之三(MFC应用程序框架分析)
  14. python一百行代码的项目_用python一百行代码实现xss扫描工具
  15. 空间数据平台SDP - 医疗药品门店数字化营销
  16. mongoDB清空数据库
  17. 【源码】色度坐标计算器:计算CIE坐标并绘制
  18. 荣耀10青春版支持鸿蒙吗,荣耀10青春版详细评测:又一款年轻群体收割机
  19. linux开组态软件,基于嵌入式Linux的组态软件实时数据库的设计
  20. 慎读书,精读书,反复读好书并学以致用

热门文章

  1. LGWR waits for event ‘DLM cross inst call completion’ 故障排除
  2. 十进制与R进制之间的转换
  3. 2019年全国职业院校技能大赛中职组“网络空间安全”正式赛卷及其“答案”
  4. 2022劳务员-通用基础(劳务员)复训题库及在线模拟考试
  5. 幼儿园介绍信(15篇)
  6. IEduChina2019国际学校展暨国际教育论坛温暖深圳
  7. 全球与中国汽车真皮内饰市场发展模式及前景趋势预测报告2022-2028年版
  8. JAVA PDF 转 PNG
  9. MySQL误删怎么办
  10. 印象笔记终于支持 Markdown 了