前面我们已经讲了整数在内存中的存储,以及相关大小端存储等概念,下面我们就来讲一下浮点数(浮点家族包括float,double,long double 类型。)在内存中的存储,其存储方式是否和整数在内存中的存储方式一致呢?下面我们简单来看一段代码来引入今天的浮点数在内存中是如何存储的!
注:浮点数的表示范围在float.h中定义
#include
int main()
{
int n = 9;
float *pFloat = (float *)&n;
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;
}
当看到这串代码时,每个同学可能都会有不同的答案,下面我们来看一下具体打印出来的结果如何!
相信很多小伙伴会想,答案为什么是这样的?怎么和我自己想的不一样呢?不用着急,下面我将为大家讲解为什么会出现这样的结果!
首先我们需要了解到整数和浮点数在内存中的存储方式是不相同的,所以我们当我们用浮点数的格式取出一个整数或者用整数的格式取出一个浮点数,就会导致我们想不到的结果!
下面我将相信为大家讲解一下浮点数是如何在内存中存储的!搬好小板凳,重点来了!
根据国际标准 IEEE (电气和电子工程协会) 754 ,任意一个二进制浮点数 V 可以表示成下面的形式:
(-1)^S * M * 2^E (-1)^S表示符号位,当 S=0 , V 为正数;当 S=1 , V 为负数。 M 表示有效数字,大于等于 1 ,小于 2 。 2^E 表示指数位。
举个简单的例子,例如十进制的5.5,其转化为二进制位101.1, 根据国际标准IEEE(电气和电子工程协会) 754,可以写成1.011*10^2。
按照上面的格式,S=0;M=1.011;E=2;
其中
前面说过, 1≤M<2 ,也就是说, M 可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。IEEE 754 规定,在计算机内部 保存M时 ,默认这个数的 第一位总是1 ,因此 可以被舍去 ,只保存后面的xxxxxx 部分。比如保存 1.01 的时候,只保存 01 ,等到 读取的时候,再把第一位的1加上去 。这样做的目的,是节省 1 位有效数字。以 32 位浮点数为例,留给 M 只有 23 位,将 第一位的1舍去以后,等于可以保存24位有效数字 。
至于指数E,情况就比较复杂。
首先, E 为一个 无符号整数(unsigned int)这意味着,如果 E 为 8 位,它的取值范围为 0~255 ;如果 E 为 11 位,它的取值范围为 0~2047 。但是,我们知道科学计数法中的E 是可以出现负数的,所以IEEE 754 规定,存入内存时 E 的真实值必须再加上一个中间数,对于 8位的E,这个中间数 是127 ;对于 1 1位的E,这个中间数是1023 。比如, 2^10 的 E 是 10 ,所以保存成 32 位浮点数时,必须保存成 10+127=137 ,即10001001 。
这时,浮点数就采用下面的规则表示,即 指数E的计算值减去127(或1023 ),得到真实值,再将有效数字M前加上第一位的1 。比如:0.5 ( 1/2 )的二进制形式为 0.1 ,由于规定正数部分必须为 1 ,即将小数点右移 1 位,则为1.0*2^(-1) ,其阶码为 -1+127=126 ,表示为01111110 ,而尾数 1.0 去掉整数部分为 0 ,补齐 0 到 23 位 00000000000000000000000 ,则其二进制表示形式为: 0 01111110 00000000000000000000000
E全为0
这时,浮点数的指数 E 等于 1-127 (或者 1-1023 )即为真实值,有效数字 M 不再加上第一位的 1 ,而是还原为 0.xxxxxx 的小数。这样做是为了表示 ±0 ,以及接近于0 的很小的数字。0 01111110 00000000000000000000000
这时,如果有效数字 M 全为 0 ,表示 ± 无穷大(正负取决于符号位 s );
看到现在,我已经将浮点数在内存中是如何存储的讲解完毕!下面我们再回到上面的题目中!
下面具体的介绍过程我都在代码块注释区详细写出!
#include
int main()
{
int n = 9;
//00000000 00000000 00000000 00001001 整数9在内存中的存储方式!
//0 00000000 00000000000000000001001 浮点数格式取出也是按照其整数存储的二进制代码
//S E M
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);//若以浮点数形式取出,则E为全0,最后结果根据规定则是一个无限接近于0的数字!
*pFloat = 9.0;
//1001.0 1.001*2^3
// 0 10000001 00100000000000000000000 //浮点数9.0在内存中的存储方式!
// S E M
printf("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);//当以整数格式取出时,则取出的是其对应的二进制转化后的结果,为一个很大的数字!
return 0;
}
后面以整数形式打印出来的浮点类型的结果转化为二进制代码和我们在内存中存储浮点数形式完全一致!证明我们的结果是正确的!
好的,今天分享的浮点数在内存中的存储到此为止,若还有疑问,欢迎各位佬们评论区留言!
希望大家点个免费的小心心哦!