最近在搞DSP,所以不可避免地会遇到浮点数,包括半精度浮点(16bit) 和单精度浮点(32bit)。
1、根据wiki百科介绍,
IEEE 754规范中规定的32bit float point的格式为:(以下引用wiki百科https://en.wikipedia.org/wiki/Single-precision_floating-point_format)
The real value assumed by a given 32-bit
binary32 data with a given biased
sign, exponent
e (the 8-bit unsigned integer), and a
23-bit fraction is
- {displaystyle (-1)^{b_{31}} imes (1.b_{22}b_{21}dots
b_{0})_{2} imes 2^{(b_{30}b_{29}dots b_{23})_{2}-127},}
which in decimal yields
-
{displaystyle { ext{value}}=(-1)^{ ext{sign}} imes left(1+sum _{i=1}^{23}b_{23-i}2^{-i}
ight) imes 2^{(e-127)}.},也可以是符号位是最高1位,
指数位,位宽8bit,这8位可以表示为8bit的有符号数,也可以表示为8bit的无符号数,当表示成8bit的无符号数时,指数的实际值 = E(指数表示的值) - 127,127被称为 exponent - bias。这样做之后指数的实际值的范围为 -126 ~ +127,而-127和+128保留做其他用处。
有效位数,也被称为尾数,24bit中最高1bit为隐式存储,且值为1,剩下的23bit显式存储为32bit中的低23bit。
上述计算公式也可以表示为,value = (-1)^sign X 2^(e - 127) X (1 + M / 2^23);(M的值为23bit表示的整数值);
2、而16bit半精度浮点的格式为:
sign bit: 1bit
exponent width: 5bit
significand: 10bit
表示的浮点数值为,alue = (-1)^sign X 2^(e - 16) X (1 + M / 2^10)。
3、单精度浮点的开根号求倒数算法
众所周知的算法是:(引用wiki百科:https://en.wikipedia.org/wiki/Fast_inverse_square_root)
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;
}
这个算法应用很广,这里主要是阐述下magic number 0x5f3759df 值的推导
- Sx, the "sign
bit", is 0 if x > 0, and 1 if x <
0 (1 bit)
- Ex = ex + B is
the "biased exponent", where B = 127 is the "exponent
bias"[note
3] (8 bits)
- Mx = mx × L,
where L = 223[note
4] (23 bits)
推导过程可参考wiki百科,
最后得出
- }
σ ≈ 0.0450466,按照这个公式计算magic number时可以使用科学计算器,计算出来的小数4舍5入后转为整数,该整数就是magic
number
而16bit半精度浮点的magic number的计算也使用该公式,这时L = 2^10,B
= 16,最后magic number = 0x5fba (或0x5fbb)
16bit开根号求倒数的代码为:
-
float16 Q_rsqrt16( float16 number )
{
short i;
float16 x2, y;
const float16 threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( short * ) &y; // evil floating point bit level hacking
i = 0x5fba - ( i >> 1 ); // what the fuck?
y = * ( float16 * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}