IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。--------------百度百科
一、浮点数的存储方式
数据类型 | 内存大小) | 内存分配 | 指数偏移 | 指数位范围 | 精度 |
float | 32位 | 符号位(s)1位 指数位(E)8位 有效数字(M)23位 | +127 | [0,255] | 小数点后6位 |
double | 64位 | 符号位(s)1位 指数位(E)11位 有效数字(M)52位 | +1023 | [0,2047] | 小数点后15位 |
任意一个浮点数都可以表现为以下形式:
- (-1)^s表示符号位,s为0表示正,s为1表示负
- 2^E表示指数位
- M表示有效数字,大于等于1,小于2。
关于M和E在存储时有另外的要求:
因为1<= M <2,所以M都写成1.xxxx的形式,所以计算机在存储M时,默认第一位总是为1,在存储时就会将这个1舍去,只保留后面的小数部分,在读取时再将1加上去,如下例 1.011,只保存011,这样可以多保留一位有效数字,如float型,M只占据23位,将1省去后,可以保留24位有效数字,精度更高。
对于E来说,首先E是一个无符号整数,是(unsigned int)。取值范围如上表所述,E为8位,它的取值范围为0-255,E为11位,它的取值范围为0~2047。但是,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数 ,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。称作指数偏移。
例:2^2的E是2,所以保存成为float型,必须保存成2+127=129,即10000001。
然后,指数E还可以再分成三种情况:
(1)E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实
值,再将有效数字M加上第一位的1
(2)E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1, 而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
(3)E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
计算机是按照如下方式去存储浮点数的:
单精度:第一位 符号位(s);第二位到第九位 数位(E);余下23位 有数字(M)
同理可得双精度,就不加以赘述了。
举例:十进制的5.5转化为二进制是101.1 = 1.011*2^2,按照上述表现形式可得
(-1)^0 * 1.011 * 2^2 即 s = 0 ,M= 1.011, E= 2;
存储时E要加上127 即 2+127 = 129 = 10000001
完整二进制表示为:
0 10000001 01100000000000000000000
十进制的 -5.5转化为二进制 -101.1 = 1.011*2^2 同理可得 :(-1)^1 * 1.011*2 ^2
即 s = 0,M= 1.011,E = 2.
同理 二进制表示为:
1 10000001 01100000000000000000000
验证代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 9;
float* pFloat = (float*)&n;//因为&n是int* 所以加个强制类型转换 float*
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
运行结果:
我们可以看到,同样的值,我们以不同的形式打印,得出来的结果大不相同。原因就是浮点型的存储和整型的存储时不一样的。我们用上述知识点分析一下结果由来:
1、n = 9 ;打印:n的值为9,整型赋值,整型拿出所以是9
2、*pFloat的值为0.000000 ,因为n =9 的二进制表示为 00000000000000000000000000001001
但是他是用浮点型的视角去看的,所以按照浮点数的存储方式解读就是:
s = 0; E= 00000000 ;M = 00000000000000000001001(E全为0的情况)
E的真实值:1-127=126 ;M= 0.00000000000000000001001
所以浮点数A= (-1)^0 * 0.00000000000000000001001 * 2 *(-126)而单精度浮点型只到读取小数点后6位,所以打印0.000000。
3、num的值为 :1091567616。*pFloat = 9.0 转为二进制 1001 = (-1)^0*1.001 * 2^3
s = 0; M =1. 001;E = 3; ---> M = 00100000000000000000000 ; E= 3+127 = 130 = 10000010;
二进制表示:01000001000100000000000000000000 。将其作为整数转为十进制打印出来就是1091567616。
4、*pFloat的值为:9.000000.浮点型存入,浮点型打印所以是9.000000.
以上就是我关于浮点型存储知识的一些理解,取经于b站比特鹏哥的C语言视频,自己做了一些总结,巩固一下所学内容,小白学习,如有缺漏,敬请指出。