vlambda博客
学习文章列表

【C语言 】(一)浮点数IEEE 754标准之规则

  • 参考文献
  1. 《深入理解计算机系统 第三版》第2.4.2节,IEEE浮点表示

  2. IEEE Std 754™-2008 第3.2、3.3、3.4节


  • 困难之一
一个诸如符合 的十进制浮点数,若用二进制小数这种“定点表示法”,对于非常大的数,其是无法有效表达的。
【C语言 】(一)浮点数IEEE 754标准之规则表示一个浮点数,转换为二进制数,要在二进制101后面跟100个0的位模式表示,这在内存中存储时无法想象的。
所以针对浮点数,其是有一套国际标准的,即IEEE 754标准。
【C语言 】(一)浮点数IEEE 754标准之规则
  • IEEE浮点表示

【C语言 】(一)浮点数IEEE 754标准之规则

s:符号,决定浮点数是正数(s=0),还是负数(s=1);

M:尾数,是一个二进制小数,根据阶码exp的不同,取值范围不同,

       1≤M<2,或0≤ M<1;

E:指数,作用是对浮点数加权,权重是2的E次幂;

  • IEEE浮点存储表示

IEEE 754将符合上述形式的浮点数存储分为三个字段,分别为:

【C语言 】(一)浮点数IEEE 754标准之规则

这三个字段根据浮点数的精度有两种常用的格式:单精度浮点格式,双精度浮点格式。

【C语言 】(一)浮点数IEEE 754标准之规则

1)“浮点存储”时的s、exp、frac与“浮点表示”时s、M、E的关系根据exp值的不同而不同,具体见下面的描述。

2)要注意浮点数与整形之间转换会存在问题,因为两种类型的存储结构不同;

  • IEEE浮点数值的分类

根据exp值的不同,浮点数被编码的值分为规格化值、非规格化值、及特殊值。
以单精度浮点数为例,分类如下表:
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

【C语言 】(一)浮点数IEEE 754标准之规则


【C语言 】(一)浮点数IEEE 754标准之规则

【C语言 】(一)浮点数IEEE 754标准之规则


  • IEEE Std 754™-2008 的描述

【C语言 】(一)浮点数IEEE 754标准之规则
【C语言 】(一)浮点数IEEE 754标准之规则
【C语言 】(一)浮点数IEEE 754标准之规则


  • 关于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));
//00‭11 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