浮点型数据,即float型数据。不同于整数型数据再内存中的简单存储方式,相对而言较难理解,有很多同学在刚接触数据类型的时候都会表示一脸懵逼,根本不理解呀!
但其实只要特别关注一下,你就能明白其中的奥秘并不困难。今天小编就以“浮点数在内存中的储存方式”为主题,与大家一起探讨~
浮点型数据是用来表示具有小数点的实数的。为什么在C语言中把实数称为浮点型数呢?在C语言中,实数是以指数形式存放在存储单元中的。
一个实数表示为指数可以有不止一种形式,如3.1459可以表示为:
3.14159×100,0.314159×101,0.0314159×102,31,14159×10-1,或314,159×10-2等。可以看到:小数点的位置是可以在314159几个数字之间、之前或之后(加0)浮动的,只要在小数点位置浮动的同时改变指数的值,就可以保证它的值不会改变。由于小数点位置可以浮动,所以实数的指数形式称为浮点数。
对于浮点类型数据,我们最需要明白一点就是:浮点数和整数的编码方式差异巨大。举个例子:
#include
int main()
{
int a = 9;
float *pFloat = (float *)&a;
printf("%f\n",*pFloat);
float b = 9.0;
float *p = &b;
printf("%f\n",*p);
return 0;
}
运行结果:
从以上结果得知浮点数的存储方式和整数是不一样的。那么,浮点数据是如何存储的呢?根据国际标准IEEE(电子与电气工程协会)规定,任何浮点数的二进制数存储都要遵循以下公式进行转换:
NUM = (-1) ^ s * M * 2 ^ E
来来来我们解释一下:
S : 当S为1时,表示为负浮点数,当S为0时,表示正浮点数
M: 表示有效数 ,1<=M<2
2^E: 表示指数
可能有些同学看到上面的公式已经心情开始浮躁了,但是不要慌,稳住,我们能赢!
想看懂上面的内容,首先了解一下浮点在内存的存储方式。如下图所示:
那么问题来了,s表示符号位,0为正数,1为负数,那好办,这个位要么0,要么1,当然负数的存储方式是不一样的,本文讨论的是正浮点的情况,浮点的存储方式,所以s为0。那e是什么呢?这八位存储的内容又是什么?
我们先确定e(指数域的二进制表示)是如何得来的,计算的e的结果需要用以下公式:
e = E + Bias
E : 从上面公式知道E为指数
E的计算方式如下:
以135.5这个浮点数为标本
(1) 取整数135转换为二进制(不知道自己用计算器或者百度)为10000111
(2) 取小数0.5转换为二进制(方法为小数乘2取整数,不懂百度)为 0.5 * 2 = 1.0,所以小数位1,
举个例子:如果小数是0.375,计算方式为
0.375 * 2 = 0.75 0
0 . 75 * 2 = 1.5 1
0.5 * 2 = 1.0 1
所以0.375转换为二进制数值为 0.011 就是 011
(3)那么可以得出135.5的二进制为10000111.1
(4)将这个数值套进公式
10000111.1 = (-1)^0 * (1.00001111)*2 ^ 7
所以得出E的值为7
Bias : 是一个等于2^k-1 – 1的偏置值(k为指数域位数,对于32位浮点数是8,对于64位浮点数而言是11,因为我的是32位系统,所以k值为8),通过此方法可以得出Bias的值为
2^8-1 – 1 = 127
那么e = 7+127 = 134 转换为二进制为 10000110
M :小数部分 , 从上方可以得出结果为 00001111
好了,这样就可以将 s , e , M
0 10000110 00001111 000000000000000
共32位.
所以得出结果,135.5在内存中的存储方式如下
0000 0000 低地址 0
1000 0000 -128(最高位1为负数)
0000 0111 7
0100 0011 高地址 67
嗯,接下来验证奇迹的时刻来了,写个代码测试以下
#include
int main()
{
float m = 135.5;
char *a = (char *)&m;
printf("0x%p = %d\n",a,*a);
printf("0x%p = %d\n",a+1,*(a+1));
printf("0x%p = %d\n",a+2,*(a+2));
printf("0x%p = %d\n",a+3,*(a+3));
return 0;
}
运行结果如下:
从结果可以得出我们的认证是正确的,哦,对了,还可以知道小编的系统是小端模式。最后奉上小编分析的鬼画符。
*小编的测试系统为32位的ubuntu 14.04
以上就是今天所有的内容啦
如果大家有什么关于浮点数的问题,欢迎在评论区留言
我们下期再见~