大家在写C语言中都用过浮点数float,和double。但是你们知道在内存中是怎么存储的吗?
C语言常用的浮点数有: float doule long doule
其中 long double 是在C语言 C99& 的新标准中增加的。
大家看一下下面这段代码,大家猜一下是多少
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;
}
但实际上输出的结果是:9 0.000000 1091567616 9.000000 这是为什么呢?接下来就要了解一下浮点数的存储方式大家就明白了。
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
V = (-1)^S * M * 2^E (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。 M表示有效数字,大于等于1,小于2。 2^E表示指数位。
那这些是什么意思呢?
十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 因为是二进制所以 底数是2,小数点向左移动了俩位所以指数是2 那么,按照上面V的格式,可以得出 S=0,M=1.01,E=2。 十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2
那么,S=1,M=1.01,E=2 在IEEE 754规定: 对于32位的浮点数,最高的1位是符号位S,接着的 8位是指数E,剩下的23位为有效数字M。
如图所示:
对于64位的浮点数,最高的1位是符号位S, 接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对有效数字M和指数E,还有一些特别规定。
至于指数E,情况就比较复杂。 首先,E为一个无符号整数(unsigned int)
比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即 10001001。
#include <stdio.h>
int main()
{
float n = 5.5;
//5.5的二进制是101.1
//所以这时
//S=0 M=1.011 E=127+2
//根据浮点数在内存中的存储模型得
//在内存中存储的是
//0 10000001 01100000000000000000000
//转成16进制为
//0100 0000 1011 0000 0000 0000 0000 0000
//0x40 b0 00 00
return 0;
}
扩展:
为什么5.5的二进制是101.1 0.5为什么转二进制会成为0.1呢 因为二进制小数点后面的计算方法是 从小数点往后1位就是2的-1次方乘以那个位置的数字得来的 0.1就是1*2的-1次方1等于0.5
我们在内存中看一下浮点数5.5的存储是不是我们上面代码计算那样
这时我们可以看到内存中的确是按这种方法存储的 由于在这里是小端存储所以16进制是反着存的
这时,浮点数就采用下面的规则表示:
比如:
0 01111110 00000000000000000000000
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值。
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及无限接近于0的很小的数字。
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
好了我们关于浮点数在内存中的存储规则就了解完了。 有关指数E我们介绍了3种情况:
关于E全为0 或者 E全为1我们了解一下就可以了。这些都是特殊情况大家只需要明白是怎么回事就可以了。
printf(“n的值为:%d\n”, n); 这句话为什么输出是 9呢?
因为n是个 int类型所以我们输出是以整形格式取出然后以%d十进制方式打印
printf(“*pFloat的值为:%f\n”, *pFloat); 这个的输出为什么是0.000000呢?
这个是对float类型的指针解引用但他指向地址是个整形 而整形类型的在计算机存储的是补码: 9转成二进制就是 00000000000000000000000000001001 而按浮点数类型拿出的话 S=0 E=0 M= 0…1010 这里就是指数E为0的时候 套用浮点数计算公式 V = (-1)^S * M * 2^E 我们拿出的是一个无限接近0的一个小数 而%f只打印6个零就不打印了所以我们打印的是: 0.000000
*pFloat = 9.0; printf(“num的值为:%d\n”, n); 这个打印为什么是1091567616
这段代码第一句话向指针指向的地址存进去了一个浮点数9.0 而浮点数的存储9.0 二进制是1001 写成科学计数法是 1.001 所以S=0 M=1.001 E=130 所以在内存存的是: 0 10000010 00100000000000000000000 转成十进制打印就是1091567616
*pFloat的值为:%f\n", *pFloat
这个是以浮点数的形式打印,而我们存进去的就是浮点数所以 打印还是9.0
希望大家有所收获呢。大家如果有什么想法或者发现什么错误发现也请周期评论区多多指出呢。博主会第一时间回复呢,希望大家喜欢!
咳咳都看到这里了:大家还不动动小手活动一下(点赞)(收藏)+(关注)!💛 💙 💜 ❤️ 💚 💔 💓 💗 💕 💞 💘 💖