寻求更好的阅读体验,请移步 :浮点数在计算机中的存储 —【Mculover666的个人博客】。
用于存储小数的数据类型是有单精度浮点型(float)和双精度浮点型(double),那么,浮点数在计算机中是以怎样的二进制代码存储的呢?
本篇将为你揭秘浮点数在计算机中的存储方式~
1. 浮点数在编程时的表示方式(书写方式)
浮点数在编程时有两种写法:
- 传统写法:直接写(eg. 0.1234)
- 科学计数法:用e表示(eg. 12.34e-2)
2. 十进制小数与二进制浮点数之间的转化
- 十进制小数 -> 二进制浮点数
- 二进制浮点数 -> 十进制小数
具体参考常用进制及其转化一文。
3. 浮点数按照IEEE 754标准存储在计算机中
IEEE 754
IEEE 754全称ANSI/IEEE Std 754-1985,是CPU和浮点运算器中广泛使用的二进制浮点算术标准。
IEEE 754标准定义了表示浮点数的格式,一些特殊数值((无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”。
IEEE 754规定了四种表示浮点数值的方式:
- 单精确度(32位)
- 双精确度(64位)
- 延伸单精确度(43比特以上,很少使用)
- 延伸双精确度(79比特以上,通常以80位实现)
IEEE 754中二进制浮点数的存储格式
IEEE 754标准中规定的二进制浮点数存储格式如图,有三个域分别对应:
- sign:最高位是符号位,0表示正数,1表示负数(对应二进制小数的符号)
- exponent:指数值的编码值(对应二进制小数的指数)
- fraction:有效值的编码值(对应二进制小数的有效值,范围:大于等于1,小于2)
所以,二进制浮点数的实际值为:
v a l u e = ( − 1 ) s i g n ∗ f r a c t i o n ∗ 2 e x p o n e n t value = (-1)^{sign} * fraction * 2^{exponent} value=(−1)sign∗fraction∗2exponent
举个例子就懂了:
eg.
十进制小数5.625转化为二进制为101.101B,按照IEEE 754标准表示为:1.01101*2^2,所以得出各个域的值为:
- sign:0
- exponent:2
- fraction:1.01101
根据这个公式,得出了IEEE 754标准中三个域分别应该存储的数,先理解到这儿即可,后面再详细讲述如何将这三个数进行编码存储。
IEEE 754中每个域的长度
在IEEE 754标准中,不同的表示方式,对应三个区域的长度也不同。
以常用的单精度和双精度来说:
- 32位单精度
- 64位双精度
接下来开始最关键的部分 —— —— 有效值和指数值是以怎样的编码存储的?
IEEE 754存储格式的有效值段(fraction)
IEEE 754中规定了有效值的范围是:大于等于1,小于2。
这意味着有效值的整数部分永远是1,所以这个可以忽略掉(不存储)整数部分的1和小数点,只存储小数部分的值即可。
这样做的好处是节省了一位,比如32位单精度本来只规定了23位用于存储有效数字的值,但实际可以存储24位有效数字的值。
eg.
之前的例子中有效值字段是1.01101B,省略掉整数部分的1,只存储01101B,右边不够的补零,所以单精度存储方式中,23位有效值字段的值是0110 1000 0000 0000 0000 000。
IEEE 754存储格式的指数段(exponent)
指数E的存储情况比较复杂。
首先,E为一个无符号整数(unsigned int)。这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,科学计数法中的E是可以出现负数的,所以IEEE 754规定,E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
再用之前的例子来说明了这个知识:
eg.
指数字段是2,在32位单精度存储时,2 + 127 = 129,所以8位指数字段存储的值是129的二进制,即:1000 0001B。
最后再讲述一下指数E的三种不同情况所表示的数:
- E不全为0或不全为1:浮点数就采用上面的规则表示,即指数E的计算值减去127(或1023)就是实际值,再补上省略掉的1。
- E全为0:浮点数的指数E等于1-127(或者1-1023),有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
- E全为1:如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)。
C语言程序验证示例结果
综合上述的讲述,示例中十进制小数5.625用32位单精度存储是:
0 10000001 01101000000000000000000
= 0100 0000 1011 0100 0000 0000 0000 0000
= 0x40b40000
下面在C语言中验证一下结果是否正确:
/**
* @ brief 验证浮点数在计算机中存储的IEEE 754标准
* @ author mculover666
* @ date 2019年6月23日14:49:35
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float i = 5.625; //0100 0000 1011 0100 0000 0000 0000 0000
int *p = &i;
printf("i = %f\n", i);
printf("i = %x\n", *p);
system("pause");
return 0;
}
/**
* 在Mingw-w64编译器下运行结果:
* ---------------------------------------
i = 5.625000
i = 40b40000
* ---------------------------------------
*/
在64位Win7系统上,用Mingw-w64编译,运行结果如下:
最后附上一个十进制小数转IEEE 754浮点数的小工具:www.styb.cn/cms/ieee_75…