【C语言 】(一)浮点数IEEE 754标准之规则
-
参考文献
《深入理解计算机系统 第三版》第2.4.2节,IEEE浮点表示
IEEE Std 754™-2008 第3.2、3.3、3.4节
-
困难之一
-
IEEE浮点表示
s:符号,决定浮点数是正数(s=0),还是负数(s=1);
M:尾数,是一个二进制小数,根据阶码exp的不同,取值范围不同,
1≤M<2,或0≤ M<1;
E:指数,作用是对浮点数加权,权重是2的E次幂;
IEEE浮点存储表示
IEEE 754将符合上述形式的浮点数存储分为三个字段,分别为:
这三个字段根据浮点数的精度有两种常用的格式:单精度浮点格式,双精度浮点格式。
1)“浮点存储”时的s、exp、frac与“浮点表示”时s、M、E的关系根据exp值的不同而不同,具体见下面的描述。
2)要注意浮点数与整形之间转换会存在问题,因为两种类型的存储结构不同;
IEEE浮点数值的分类
exp |
frac |
M | E | Bias | 意义 |
1~254 |
0≤frac<1 |
1+frac |
exp-Bias |
127 |
规格化数 |
0 |
0 |
0 | 1-Bias | 127 |
±0.0 |
0 |
非0 |
非0 |
1-Bias |
127 |
非规格化数 |
255 |
0 |
0 |
±∞ |
||
255 |
非0 |
非0 |
NaN |
IEEE Std 754™-2008 的描述
关于NaN、INF
在一些情况会出现无效的浮点数,例如除0,例如负数求平方根等,像这类情况,获取到的浮点数的值是无效的。
NaN 即 Not a Number 非数字
INF 即 Infinite 无穷大
通常无效浮点数的内存表示方法是:
根据IEEE 754标准:
阶码全1,尾数全0表示无穷大INF。例如1.0/0.0
阶码全1,尾数非全0的表示无效数NaN。例如:求负数的平方根,例如0.0/0.0。
https://blog.csdn.net/chunyexiyu/article/details/39179735
INF无穷大:在doulbe/float时的取值
float f = 0; (4字节 1位符号位,8位指数,23位小数,指数偏移127)
*(UINT*)&f = 0x7F800000L;//正无穷
(二进制 [0111 1111] [1000 0000] [0000 0000] [0000 0000])
*(UINT*)&f = 0xFF800000L;//负无穷
(二进制 [1111 1111] [1000 0000] [0000 0000] [0000 0000])
https://blog.csdn.net/chunyexiyu/article/details/39179735
double var = 0; (8字节 1位符号位,11位指数,52位小数,指数偏移1023)
// 因为通常是little endian,所以通常修改其前后4个字节 UINT* pVar = ((UINT*)&var) + 1;
*(pVar) = 0x7FF00000L;//正无穷
*(pVar) = 0xFFF00000L;//负无穷
https://blog.csdn.net/chunyexiyu/article/details/39179735
IEEE 浮点数实验
以单精度浮点数举例,查看浮点数存储到内存后其与IEEE 754规则是否相匹配。
测试环境:Windows 10系统,Visual Studio 2013
//规格化存储
float f = 20.59375;
printf("%f,%x\n", f,*(unsigned int*)(&f));
//0100 0001 1010 0100 1100 0000 0000 0000
//规格化存储
float f1 = 5.0;
printf("%f,%x\n", f1, *(unsigned int*)(&f1));
//0100 0000 1010 0000 0000 0000 0000 0000
//规格化存储
float f2 = 1.25;
printf("%f,%x\n", f2, *(unsigned int*)(&f2));
//0011 1111 1010 0000 0000 0000 0000 0000
//规格化存储
float f3 = 0.25;
printf("%f,%x\n", f3, *(unsigned int*)(&f3));
//0011 1110 1000 0000 0000 0000 0000 0000
//规格化存储
float f4 = 1.2;
printf("%f,%x\n", f4, *(unsigned int*)(&f4));
//0 011 1111 1 001 1001 1001 1001 1001 1010
//非规格化,接近于0
float f5 = 0.00000000000000000000000000000000000000005;
printf("%f,%x\n", f5, *(unsigned int*)(&f5));
//0000 0000 0000 0000 1000 1011 0110 0001
//0.000000,8b61
//非规格化,+0
float f51 = +0.0;
printf("%f,%x\n", f51, *(unsigned int*)(&f51));
//0.000000,0
//非规格化,-0
float f52 = -0.0;
printf("%f,%x\n", f52, *(unsigned int*)(&f52));
//-0.000000,80000000
//特殊值 正无穷大
float f6 = 9999999999999999999999999999999999999999999999999.0;
printf("%f,%x\n", f6, *(unsigned int*)(&f6));
//0 111 1111 1 000 0000 0000 0000 0000 0000
// 1.#INF00,7f800000
//特殊值 负无穷大
float f7 = -9999999999999999999999999999999999999999999999999.0;
printf("%f,%x\n", f7, *(unsigned int*)(&f7));
//1 111 1111 1 000 0000 0000 0000 0000 0000
//-1.#INF00,ff800000
--------------------------------------------------------------------------------------------
WW 于2020/03/18 午12:00