之前的那篇转载浮点数的存储转载内容比较粗糙。今天又花了点时间试了个具体的例子。部分内容摘自参考。
以32bit浮点数 0.123456789的存储为例,通过在线进制转换获得其16进制表示为
3DFCD6E9
对应的二进制为:
0011 1101 1111 1100 1101 0110 1110 1001
朴素二进制表示
0.123456789没有整数部分,所以直接看小数部分表示。
0.123456789 * 2 = 0.246913578 取整数部分0
0.246913578 * 2 = 0.493827156 取整数部分0
0.493827156 * 2 = 0.987654312 取整数部分0
0.987654312 * 2 = 1.975308624 取整数部分1,去掉整数部分
0.975308624 * 2 = 1.950617248 取1
0.950617248 * 2 = 1.901234496 取1
0.901234496 * 2 = 1.802468992 取1
...
最后将取的0,1按顺序排列得到:
0001 111 1001 10.....
所以最后0.123456789的二进制朴素表示形式是:
(0.0001 111 1001 10) 2
科学计数法(规格化处理)
在计算机内,对非0值的浮点数,要求尾数域的最高有效位应为1。本身0.123456789已经满足科学计数法,但是其二进制表示形式仍有多余的前导0。二进制原码的规格化数的表现形式:(0正1负)
正数 0.1xxxxxx
负数 1.1xxxxxx
尾数的最高位始终为1,可以被忽略。
IEEE754 标准:
-
尾数用原码,且隐藏尾数最高位。
-
阶码使用“移码”,基固定为2
(0.0001 1111 1001 10...) 2 变为(1. 1111 1001 10...)2 * 2 -(100)2
第一个1向左移动了4位,并不是说将原数变为了负数,而是第一个1可以忽略,所以临时挪到小数点左边去了,最后在统计数值时,将这个1忽略不计。4的二进制为100,由于是向左移动,所以需要乘以 2-4。
指数偏移值(exponent bias),是指浮点数表示法中的指数域
的编码值为指数的实际值加上某个固定的值,IEEE 754
标准规定该固定值为2^{e-1}-1
,其中的e
为存储指数的比特位的长度(float为8,double为11)。
以单精度浮点数为例,它的指数域是8个比特,固定偏移值是 2^{8-1}-1=128-1=127
。单精度浮点数的指数部分实际取值是从-127到128(8位有符号二进制的取值范围)。例如指数实际值为17
,在单精度浮点数中的指数域编码值为144
,即127 + 17
。
在当前例中,127 + (-4) = (0111 1111)2 - (0000 0100)2 = (0111 1011)2
所以,最后阶码为(0111 1011)2 ,尾数为(1111 1001 10...)2 ,拼起来得到:
符号位 | 阶码 | 尾数 | |
---|---|---|---|
我们的推算 | 0 | 0111 1011 | 1111 1001 10... |
在线转换获得的数值 | 0 | 011 1101 1 | 111 1100 1101 0110 1110 1001 |
浮点数的表示精度
float的有效位为6~7位, double的有效位为15~16位 。
有效位数只和规格化浮点数的尾数部分有关,而尾数部分的位数是23位。
二进制 | 十进制 |
---|---|
2-23 | 0.000000119209289 |
2-22 | 0.0000002384185791 |
2-21 | 0.0000004768371582 |
2-20 | 0.0000009536743164 |
2-19 | 0.000001907348632 |
2-23 和 2-22 之间是存在间隔的,即0.0000001和0.0000002之间的小数我们是没有办法描述的,因此23位尾数最多只能描述到小数点后第7位;此外,我们通过四舍五入可以很容易发现0.0000003=0.0000004=2-23 + 2-22 这表明第7位有效数字只是部分准确。而第6位及之前的都是可以准确描述的,因此我们说float的有效位为6~7位。
浮点数分布
通过上面的分析可以发现,尽管浮点数表示的范围很广,但由于精度损失的存在,加上幂次的放大作用,一个浮点数实际上是表示了周围的一个有理数区间。如果将浮点数绘制到一个数轴上,直观上看,靠近0的部分,浮点数出现较密集。越靠近无穷大,浮点数分布越稀疏,一个浮点值代表了周围一片数据。如下图所示。从这个意义上来说,浮点数不宜直接比较相等,它们是代表了一个数据范围。实际应用中,如果要使用浮点数计算,一定要考虑精度问题。在满足精度要求的前提下,计算结果才是有效的。
Comments