详细解析Fast Inverse Square Root

详细解析Fast Inverse Square Root算法(

目前已被math库收录
学习价值更重要
该内容仅针对32位编码架构

Fast Inverse Square Root算法是用来快速计算如开方的倒数计算:

F I S q r t ( x ) = 1 x FISqrt(x) = \frac{1}{\sqrt{x}} FISqrt(x)=x 1

⟺ F I S q r t ( x ) = x − 1 2 \Longleftrightarrow FISqrt(x) =x^{-\frac{1}{2}} FISqrt(x)=x21

零、Fast Inverse Square Root算法代码:

float FISqrt(float const number)
{
	long i;
	float x2;
	float 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 ) );
	return y
}

一、背景

(一) IEEE 754 浮点数表示法(数值转二进制码)

要看懂这个代码,就必须了解浮点数是如何在2进制中存储的。IEEE754规定了现代计算机浮点数的存储方式。

IEEE 754 浮点数表示法其实就是二进制版本的科学计数法。

例:

1678.4125 1678.4125 1678.4125

1.使用十进制科学计数法表示:

1.6784125 × 1 0 3 1.6784125 \times 10^3 1.6784125×103

2.使用二进制科学计数法表示:

(1)将 1678.4125 1678.4125 1678.4125 转换为二进制数:

    整数部分: 167 8 ( 10 ) = 1101000111 0 ( 2 ) 1678_{(10)} =11010001110_{(2)} 1678(10)=11010001110(2)

    为了学习我们进行手动计算:

在这里插入图片描述
    小数部分: 0.412 5 ( 10 ) = 0.0110 1001 1001 … ( 2 ) 0.4125_{(10)}=0.0110 \quad1001\quad1001 \dots_{(2)} 0.4125(10)=0.011010011001(2)

在这里插入图片描述
     ⟹ 1678.412 5 ( 10 ) = 11010001110.0110100110011001 … ( 2 ) \Longrightarrow1678.4125_{(10)} =11010001110.0110 10011001 1001\dots_{(2)} 1678.4125(10)=11010001110.0110100110011001(2)

(2)将 11010001110.0110100110011001 … 11010001110.0110 100110011001\ldots 11010001110.0110100110011001改写成2进制科学记数法:
11010001110.0110100110011001 … = 1.10100011100110100110011001 … × 2 10 11010001110.0110 100110011001\ldots=1.10100011100110100110011001 \ldots \times 2^{10} 11010001110.0110100110011001=1.10100011100110100110011001×210

(3)将 1.10100011100110100110011001 … × 2 10 1.10100011100110100110011001 \ldots \times 2^{10} 1.10100011100110100110011001×210 存入64位二进制码中。

  说明

  为达到最大限度利用64位二进制码,我们只存储最有效的部分:
  ①:符号值 sign
  ②:指数值 Exponent(显然不用存储底数2,因为二进制必定是2)
  ③:小数值 Mantissa(显然不用存储整数部分1,因为科学技术法必定有整数部分1)

现在来规划32位码,将其分割成3个部分以存储上述3个重要内容,如下:

在这里插入图片描述

  ① 符号位:
  1 bit:0表示正数,1表示负数

  ② 指数位:
  8 bit:取值 [ 0,255 ] 。但是为了表示负指数,所以以 127 作为计算分界点,将取值范围变为 [ -127,127 ] 。也就是说:在二进制转浮点数时,需要将二进制码的指数值减 127 才能得到真实的指数值。如: 1.2 × 2 4 1.2\times2^{4} 1.2×24,在二进制指数位实际存储的是127+4的二进制码,也就是10000011。

  ③ 小数位:
  23 bit: 直接放入二进制小数位即可

  实际存入
+ 1.10100011100110100110011001 … × 2 10 +1.10100011100110100110011001 \ldots \times 2^{10} +1.10100011100110100110011001×210
在这里插入图片描述

注意:

  这里就产生了截断误差

  原本小数位是: 10100011100110100110011001 … 10100011100110100110011001 \ldots 10100011100110100110011001

  现在小数位是: 10100011100110100110011 10100011100110100110011 10100011100110100110011

  如果转换回来:

  二进制码:      0 10001001 10100011100110100110011 0\quad10001001\quad10100011100110100110011 01000100110100011100110100110011

  二进制科学计数法:  1.10100011100110100110011 × 2 10 1.10100011100110100110011\times2^{10} 1.10100011100110100110011×210

  二进制:       11010001110.0110100110011 11010001110.0110100110011 11010001110.0110100110011

  十进制:       1678.4124755859375 1678.4124755859375 1678.4124755859375

  差值:         ∣ 1678.4125 − 1678.4124755859375 ∣ = 0.0000244140625 = 2.44 × 1 0 − 5 < 1 0 − 4 |1678.4125-1678.4124755859375| = 0.0000244140625 =2.44\times10^{-5}<10^{-4} 1678.41251678.4124755859375=0.0000244140625=2.44×105<104

所以在浮点数判断时,通常写作:

//仅针对 32 位架构,当代 64 位架构缩小到 e-6
if( abs(a,b) < e-4 )
{
	printf("float a is equal to float b\n");
}

(二) IEEE 754 浮点数表示法(二进制码转数值)

在第一节中,我们了解了IEEE 754二进制码由
S i g n E x p o n e n t M a n t i s s a Sign\quad Exponent\quad Mantissa SignExponentMantissa

组成,那么计算机如何将这3个二进制数 S S S E E E M M M 还原成数值 V V V

1. 以M和E代表数值

根据 IEEE 754 原理,我们逆向可得公式:

V = ( 1 + M × 2 23 ) × 2 E − 127 V = (1+M\times2^{23})\times2^{E-127} V=(1+M×223)×2E127

即:

V = ( 1 + M 2 23 ) × 2 E − 127 V = (1+\frac{M}{2^{23}})\times2^{E-127} V=(1+223M)×2E127

我们来验证一下,还是以 1678.412 5 ( 10 ) 1678.4125_{(10)} 1678.4125(10) 举例:

10 进制数值: 1678.4125 1678.4125 1678.4125

2 进制数值: 11010001110.0110100110011001 … 11010001110.0110100110011001\ldots 11010001110.0110100110011001

2 进制码: 0 10001001 10100011100110100110011 0\quad10001001\quad10100011100110100110011 01000100110100011100110100110011

则,我们可以得到3个二进制数:

S = 0 S = 0 S=0

E = 10001001 E = 10001001 E=10001001

M = 10100011100110100110011 M = 10100011100110100110011 M=10100011100110100110011

∵ M = 10100011100110100110011 \because \quad M = 10100011100110100110011 M=10100011100110100110011

⟹ M 2 23 = 0.10100011100110100110011 \Longrightarrow \frac{M}{2^{23}} = 0. 10100011100110100110011 223M=0.10100011100110100110011

⟹ 1 + M 2 23 = 1.10100011100110100110011 \Longrightarrow 1+\frac{M}{2^{23}} = 1. 10100011100110100110011 1+223M=1.10100011100110100110011

∵ E = 1000100 1 ( 2 ) \because \quad E= 10001001_{(2)} E=10001001(2)

⟹ E − 12 7 ( 10 ) = 137 − 127 = 10 \Longrightarrow E-127_{(10)} = 137-127=10 E127(10)=137127=10

⟹ 2 E − 12 7 ( 10 ) = 2 10 \Longrightarrow2^{E-127_{(10)}} = 2^{10} 2E127(10)=210

∴ V = ( 1 + M 2 23 ) × 2 E − 127 = 1.10100011100110100110011 × 2 10 \therefore V = (1+\frac{M}{2^{23}})\times2^{E-127} = 1. 10100011100110100110011\times2^{10} V=(1+223M)×2E127=1.10100011100110100110011×210

∴ V = 11010001110.011010011001 1 ( 2 ) \therefore V = 11010001110.0110100110011_{(2)} V=11010001110.0110100110011(2)

∴ V = 1678.412475585937 5 ( 10 ) \therefore V = 1678.4124755859375_{(10)} V=1678.4124755859375(10)

(在第一节说明了这里产生了截断误差)

2. 以M和E代表二进制码

V = M + 2 23 E V = M+2^{23}E V=M+223E

还是以 1678.412 5 ( 10 ) 1678.4125_{(10)} 1678.4125(10) 举例:

10 进制数值: 1678.4125 1678.4125 1678.4125

2 进制数值: 11010001110.0110100110011001 … 11010001110.0110100110011001\ldots 11010001110.0110100110011001

2 进制码: 0 10001001 10100011100110100110011 0\quad10001001\quad10100011100110100110011 01000100110100011100110100110011

则,我们可以得到3个二进制数:

S = 0 S = 0 S=0

E = 10001001 E = 10001001 E=10001001

M = 10100011100110100110011 M = 10100011100110100110011 M=10100011100110100110011

那么:

2 23 E = 10001001 00000000000000000000000 M = 10100011100110100110011 M + 2 23 E = 10001001 10100011100110100110011 \begin{aligned} 2^{23}E &= 10001001&00000000000000000000000\\ M &= &10100011100110100110011\\M+2^{23}E &=10001001&10100011100110100110011\end{aligned} 223EMM+223E=10001001==10001001000000000000000000000001010001110011010011001110100011100110100110011

⟹ V = M + 2 23 E \Longrightarrow V =M+2^{23}E V=M+223E

3. 重要推论:

V = M + 2 23 E = ( 1 + M 2 23 ) × 2 E − 127 V=M+2^{23}E = (1+\frac{M}{2^{23}})\times2^{E-127} V=M+223E=(1+223M)×2E127


(三) IEEE 754 浮点数表示法(神奇的性质)

既然:

V = ( 1 + M 2 23 ) × 2 E − 127 V = (1+\frac{M}{2^{23}})\times2^{E-127} V=(1+223M)×2E127

那么对等式左右两边取对数可得:

log ⁡ 2 V = log ⁡ 2 [ ( 1 + M 2 23 ) × 2 E − 127 ] = log ⁡ 2 [ ( 1 + M 2 23 ) ] + log ⁡ 2 2 E − 127 ] = log ⁡ 2 [ ( 1 + M 2 23 ) ] + E − 127 \begin{aligned} \log_2V &= \log_2[ (1+\frac{M}{2^{23}})\times2^{E-127}]\\ &= \log_2[ (1+\frac{M}{2^{23}})]+\log_22^{E-127}]\\ &=\log_2[ (1+\frac{M}{2^{23}})] +E-127\\ \end{aligned} log2V=log2[(1+223M)×2E127]=log2[(1+223M)]+log22E127]=log2[(1+223M)]+E127

∵ M ∈ [ 0 , 1.1111111111111111111111 × 2 22 ] \because M\in[0,1.1111111111111111111111\times2^{22}] M[0,1.1111111111111111111111×222]

⟹ M 2 23 ∈ [ 0 , 1 ) \Longrightarrow\frac{M}{2^{23}}\in[0,1) 223M[0,1)

∵ log ⁡ 2 ( 1 + x ) ≈ x + δ \because \log_2(1+x) \thickapprox x+\delta log2(1+x)x+δ

∴ log ⁡ 2 [ ( 1 + M 2 23 ) ] + E − 127 ≈ M 2 23 + δ + E − 127 ≈ M 2 23 + E − 127 + δ ≈ 1 2 23 ( M + 2 23 E ) − 127 + δ \begin{aligned} \therefore \log_2[ (1+\frac{M}{2^{23}})] +E-127 &\thickapprox \frac{M}{2^{23}}+\delta+E-127\\&\thickapprox \frac{M}{2^{23}}+E-127+\delta\\ &\thickapprox \frac{1}{2^{23}}(M+2^{23}E)-127+\delta\end{aligned} log2[(1+223M)]+E127223M+δ+E127223M+E127+δ2231(M+223E)127+δ

所以得到一个重要推论:

l o g 2 V = 1 2 23 V − 127 + δ log_{2}V =\frac{1}{2^{23}}V-127+\delta log2V=2231V127+δ


(四)求解

要求 y = 1 x y=\frac{1}{\sqrt{x}} y=x 1

即求 y = x − 1 2 y=x^{-\frac{1}{2}} y=x21

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值