浮点数零的格式定义,及其引发的潜在问题
1. 浮点数的定义
先说说浮点数的表示方法。任意二进制数N可以写成
N
=
(
−
1
)
s
×
2
e
×
M
N = (-1)^s\times2^e\times M
N=(−1)s×2e×M 的形式,其中 s是符号位,e是指数,M 称为浮点数的尾数,是一个纯小数。参照 IEEE R32.24 标准,看看 float32 的格式:
下面我们来看一个实际例子, 8.25 8.25 8.25 用十进制表示是 82.5 × 1 0 − 1 82.5 \times 10^{-1} 82.5×10−1, 那么用二进制表示是多少呢?
8.25 → 1000.01 × 2 0 → 1.00001 × 2 3 (1) \tag1 8.25 \to 1000.01\times 2^0 \to 1.00001 \times 2^3 8.25→1000.01×20→1.00001×23(1)
那么好啊,既然所有的二进制都可以表示成1.xxx * 2^xxx,那么小数点前面的肯定都是1了所以在存储到内存的时候默认都是1.xxx就好了,也没必要在内存中存储1这个bit了所以23bit的尾数部分,可以表示的精度却变成了24bit,道理就是在这里。
因此,32 位浮点数的实际表达形式变成了如下形式:
N
=
(
−
1
)
s
×
2
e
×
(
1
+
M
)
(2)
\tag2 N=(-1)^s \times 2^e \times (1 + M)
N=(−1)s×2e×(1+M)(2)
对于指数部分,因为指数可正可负,8位的指数位能表示的指数范围就应该为:-127 ~ 128了,所以指数部分的存储采用移位存储,存储的数据为原数据+127,下面就看看8.25在内存中真正的存储方式。
这样的话我们得到 8.25 的 float32 表示方法:
符号位 = 0
阶码 = 127 + 3 = 130
尾数 = 00001000....
2. 浮点数零
按照上面的定义,当
s
=
0
,
e
=
0
,
M
=
0
s=0,e=0,M=0
s=0,e=0,M=0 时,实际上表示的数值应该是
N
=
(
−
1
)
0
×
2
−
127
×
(
1
+
0
)
=
2
−
127
N=(-1)^0 \times 2^{-127} \times (1 + 0) = 2^{-127}
N=(−1)0×2−127×(1+0)=2−127
于是,我们发现,按照前面的定义,数字 0 是无法表示的。所以 IEEE R32.24 标准强行规定,
s
=
0
,
e
=
0
,
M
=
0
s=0,e=0,M=0
s=0,e=0,M=0 时,
N
=
0
N=0
N=0。
3. 浮点数在零附近的分布
我们只看正数吧!从数字 0 开始,从小到大列举最小的五个浮点数。
0
(
−
1
)
0
×
2
−
127
×
(
1
+
2
−
23
)
=
2
−
127
+
2
−
150
(
−
1
)
0
×
2
−
127
×
(
1
+
2
−
22
)
=
2
−
127
+
2
×
2
−
150
(
−
1
)
0
×
2
−
127
×
(
1
+
(
2
−
23
+
2
−
22
)
)
=
2
−
127
+
3
×
2
−
150
(
−
1
)
0
×
2
−
127
×
(
1
+
2
−
21
)
=
2
−
127
+
4
×
2
−
150
0\\ (-1)^0 \times 2^{-127}\times (1+2^{-23}) = 2^{-127}+2^{-150}\\ (-1)^0 \times 2^{-127}\times (1+2^{-22}) = 2^{-127}+2\times 2^{-150}\\ (-1)^0 \times 2^{-127}\times (1+(2^{-23} + 2^{-22})) = 2^{-127}+3\times2^{-150}\\ (-1)^0 \times 2^{-127}\times (1+2^{-21}) = 2^{-127}+4\times2^{-150}\\
0(−1)0×2−127×(1+2−23)=2−127+2−150(−1)0×2−127×(1+2−22)=2−127+2×2−150(−1)0×2−127×(1+(2−23+2−22))=2−127+3×2−150(−1)0×2−127×(1+2−21)=2−127+4×2−150
即
0
2
−
127
+
1
×
2
−
150
2
−
127
+
2
×
2
−
150
2
−
127
+
3
×
2
−
150
2
−
127
+
4
×
2
−
150
2
−
127
+
5
×
2
−
150
0\\ 2^{-127}+1\times2^{-150}\\ 2^{-127}+2\times2^{-150}\\ 2^{-127}+3\times2^{-150}\\ 2^{-127}+4\times2^{-150}\\ 2^{-127}+5\times2^{-150}\\
02−127+1×2−1502−127+2×2−1502−127+3×2−1502−127+4×2−1502−127+5×2−150
请注意,0 与其后面的最小数据增量是 2 − 127 2^{-127} 2−127,而后续的其他数据的增量是 2 − 150 2^{-150} 2−150。也就是说,数字在渐渐减少到 0 的过程中突然降到了 0。 为了减少 0 与最小数字和最小数字与次小数字之间步 长的突然下跌,subnormal 规定:当指数位全 0 的时候,指数表示为 -126 而不是 -127( 和指数为最低 位为 1 一致)。 然而公式改成 ( − 1 ) s × M × 2 e (-1)^s \times M \times 2^e (−1)s×M×2e, M 不再 +1, 这样最小的数字就变成 2 − 23 × 2 − 126 2^{- 23} \times 2^{- 126} 2−23×2−126, 次小的数字变成 2 − 22 × 2 − 126 2^{- 22} \times 2^{-126} 2−22×2−126, 每两个相邻 subnormal 数字 之差都是 2 − 23 × 2 − 126 2^{-23} \times 2^{-126} 2−23×2−126, 避免 了 突然 降到 0。
相关文章
- Html Table用JS导出excel格式问题 导出EXCEL后单元格里的000412341234会变成412341234 7-14 会变成 2018-7-14(7月14) 自定义格式 web利用table表格生成excel格式问题 js导出excel增加表头、mso-number-format定义数据格式 数字输出格式转换 mso-number-format:"@"
- 日期格式转换方法整理
- Aspose.Words for .NET使用表格教程之应用格式(4)——如何使用表的替代文本和表位的调整
- Google Earth Engine(GEE)——下载中国区域内的MCD19A2 AOD数据(tif格式)
- Allegro格式PCB转换成Pads操作指导
- c#读取string类型的xml格式的字符串
- linux下如何查看磁盘分区所使用的文件系统格式?
- 一个完整的类用来读取OpenSSL生成的pem格式的x509证书(C#)
- BLE 广播格式定义
- 【原创】Js:日期处理(日期格式必须【yyyy-mm-dd】才能转成long的毫秒!其他的不是【年-月-日】的格式,结果会是【NaN】)
- 多格式无水印录屏软件
- easyUI 验证控件应用、自己定义、扩展验证 手机号码或电话话码格式