✨✨欢迎大家来到Celia的博客✨✨
🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉
所属专栏:C语言
目录
引言
我们知道,整型数据在内存中以补码的形式存储,字符型数据在内存中以ASCII码的形式存储,其本质都是一个二进制序列,但在C语言中,浮点型的存储方式与其他数据类型大不相同,本篇文章将会简单介绍浮点型数据在内存中的存储方式。
引例
我们先来看接下来的代码,它的输出结果是什么?
#include<stdio.h>
int main()
{
int a = 5;
float* p = (float*)&a;
printf("%f\n", *p);//打印指针p所指向的数据
*p = 6.0;
printf("%d\n", a);//以整型形式打印a变量
return 0;
}
运行结果:
是不是和预想的不同?这个例子能有效地证明浮点型数据在内存中有着独特的存储方式。
一、浮点型在内存中的存储方式
1.1 国际标准IEEE754
“IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用,IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。”
国际标准IEEE(电气和电子工程协会)754规定了任意一个浮点数都可以表示成以下的形式:
- V = (-1)^S * M * 2^E
- (-1)^S表示符号位,用于表示正负
- M为有效数字(1<M<2)
- 2^E表示指数位
比如:
- 十进制的5.0可以表示成二进制为:101.0,相当于(-1)^0 * 1.01 * 2^2
- 按照以上形式:S=0,M=1.01,E=2
- 所以浮点型的存储可以理解为是对S,M,E的存储
1.2 浮点型在内存中的存储过程
1.2.1 单精度与双精度的存储模型
1.2.2 有效数字 M 和指数 E 的特殊规定
(1)有效数字M
有效数字M的范围始终是1<M<2,相当于1.xxxxxxx,其中,xxxxxx表示小数部分,在实际存储过程中,往往会省略有效数字最前面的 1 ,只保存小数部分,等到需要取出浮点型数据的时候,再把1加到最前面,这样做可以实现多存一位小数位,实现更高的精度。
(2)指数E
在国际标准IEEE754中规定了E是一个无符号的整数(unsigned int)。
这就说明,如果E是8位,它能表示的数据范围为0~255,如果E为11位,它能表示的数据范围为0~2047。但是在实际的科学计数法中,指数是可能出现负数的,(比如0.5可以表示为(-1)^0 * 1.0 * 2^(-1))但是E为无符号整型,这就使得它无法储存负数。为了解决这一问题,IEEE754规定,设置一个中间量,存入内存时E的真实值必须加上这个中间量,保证存入E的值为正数,在取出E时再减去中间量,这样一来,指数为负数时的存储问题就得到了解决。
单精度中间量(8位):127
双精度中间量(11位):1023
二、浮点数在内存中取的过程
2.1 E不全为0也不全为1
在这种情况下,浮点数会采用以下规则取出并进行相应的转换:
- 将指数的值减去中间量,得到真实值
- 将有效数字M加上最前面的1
比如 :0.5 的二进制表示为0.1,按照国际标准IEEE754可以表示为 (-1)^0 * 1.0 * 2^(-1)
存储时的S为0,M为0(去掉了最前面的1并且向后补齐0),E为-1+127 = 126,以下是二进制的存储方式(单精度):
0 01111110 00000000000000000000000 // 符号S 指数E 有效数字M
2.2 E全为0
这种情况下,浮点数的指数E转换后的真实值为-127或-1023,说明这个数是一个很小的数,这时有效数字不再加上最前面的1,而是表示为0.xxxxxx的小数,用来近似±0的小数。
2.3 E全为1
这种情况下,浮点数的指数E转换后的真实值为128或1024,说明这是一个很大的数,表示±无穷大。
三、引例解析
了解了这些规则后,我们再回过头来看引例中的代码
#include<stdio.h> int main() { int a = 5; float* p = (float*)&a; printf("%f\n", *p);//打印指针p所指向的数据 *p = 6.0; printf("%d\n", a);//以整型形式打印a变量 return 0; }
我们先来看a变量,5的二进制表示为:
00000000000000000000000000000101
但是在打印指针p所指向的数据a的时候是按浮点型打印,编译器会按照取浮点型的方式去理解这个二进制序列:
0 00000000 00000000000000000000101 // 符号 指数 有效数字
显而易见,指数部分全为0,编译器会认为这是一个很小的数,打印结果为0.000000
当我们把6.0这个浮点型数据通过指针p赋值给a的内存时,会按存储浮点型数据的方式进行存储,二进制序列如下:
0 10000001 10000000000000000000000 // 符号 指数 有效数字
按照这种方式存储之后,如果按整形数据进行打印的话,编译器在取出这个二进制序列时,并不会按照浮点型的方式取出,而是把它当作一串补码取出,打印出来自然就是很大的数了。
以上就是关于浮点型数据在内存中存储的全部内容啦~