快速求平方根

1. 前置知识

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值