浮点型在内存中的存储(建议收藏食用)
Posted 哆啦A梦_PJYA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浮点型在内存中的存储(建议收藏食用)相关的知识,希望对你有一定的参考价值。
文章目录
浮点型在内存中的存储
概念📚
整数型表示大小范围可在<limits.h>头文件中查看
浮点型表示大小范围可在<float.h>头文件中查看
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数 V V V可以表示成下面的形式:
( − 1 ) S × M × 2 E (-1)^S \\times M \\times 2^E (−1)S×M×2E
- ( − 1 ) S (-1)^S (−1)S表示符号位,当 S = 0 S=0 S=0, V V V为正数;当 S = 1 S=1 S=1, V V V为负数。
- M M M表示有效数字,大于等于1,小于2。( 1 ⩽ M < 2 1\\leqslant M < 2 1⩽M<2)
- 2 E 2^E 2E表示指数位。
举栗子🌰
🌰1: 十进制的5.5转换为二进制
- 5.5转换为二进制为:101.1
- 小数点前的5转换为二进制为:101( 2 2 + 2 0 = 5 2^2+2^0=5 22+20=5)
- 小数点后的5转换为二进制为:1( 2 − 1 = 1 2 1 = 0.5 2^{-1}=\\frac{1}{2^1}=0.5 2−1=211=0.5)
- 改为二进制的科学计数法形式: 1.011 × 2 2 1.011\\times2^2 1.011×22
- 改为IEEE 754标准公式形式:
(
−
1
)
0
×
1.011
×
2
2
(-1)^0\\times1.011\\times2^2
(−1)0×1.011×22
S = 0 ; M = 1.011 ; E = 2 S=0;M=1.011;E=2 S=0;M=1.011;E=2
🌰2: 十进制的9.0转换为二进制
- 9.0转换为二进制为:1001.0
- 改为二进制的科学计数法形式: 1.001 × 2 3 1.001\\times2^3 1.001×23
- 改为IEEE 754标准公式形式:
(
−
1
)
0
×
1.001
×
2
3
(-1)^0\\times1.001\\times2^3
(−1)0×1.001×23
S = 0 ; M = 1.001 ; E = 3 S=0;M=1.001;E=3 S=0;M=1.001;E=3
IEEE 754规定👮♂️: 对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
IEEE 754规定👮♀️: 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
存🎯
IEEE 754对有效数字M和指数E,还有一些特别规定👮♂️:前面说过, 1 ⩽ M < 2 1\\leqslant M < 2 1⩽M<2 ,也就是说,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。
有效数字M📌:在计算机内部保存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;对于11位的指数位E,这个中间数是1023。比如, 2 10 2^{10} 210的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001( 2 7 + 2 3 + 2 0 = 137 2^7+2^3+2^0=137 27+23+20=137)。
举栗子🌰
float f = 5.5f;
- 转化为二进制:101.1(转换为二进制的过程)
- 改为科学计数法: 1.011 × 2 2 1.011\\times2^2 1.011×22
- 改为IEEE 754标准公式形式: ( − 1 ) 0 × 1.011 × 2 2 (-1)^0\\times1.011\\times2^2 (−1)0×1.011×22
- S = 0 ; M = 1.011 ; E = 2 S=0;M=1.011;E=2 S=0;M=1.011;E=2
- 32位单精度浮点型E的存储: E + 127 = 129 E + 127 = 129 E+127=129
- S = 0 S = 0 S=0 对应二进制位:0
- E = 129 E = 129 E=129 对应二进制位:10000001( 2 7 = 128 2^7=128 27=128)
- M = 1.011 M = 1.011 M=1.011(存储的仅是011)对应的二进制位:011 0000000000 0000000000(后面补0)
如果想在编译器中查看内存,我们可以将这段二进制序列转化为十六进制方便查看对比:
01000000101100000000000000000000
取🎈
指数E从内存中取出将会分为三种情况👮♀️:
- E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
例如下面这一个二进制序列:
E = 126 − 127 = − 1 E = 126 - 127=-1 E=126−127=−1
M = 0 M = 0 M=0
转化为科学计数法: 0.0 × 2 − 1 0.0\\times2^{-1} 0.0×2−1
转化为二进制则为:0.1(则图示二进制序列的值为0.5)
- E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示 ± 0 \\pm0 ±0,以及接近于0的很小的数字。
E在二进制序列中表示的值是加上127之后的值,如果E是全0的话,那么E在没有存储之前的值就应该是-127。E是指数位,想象一下 2 − 127 = 1 2 127 2^{-127}=\\frac{1}{2^{127}} 2−127=21271是一个多么小的数字鸭?在不考虑符号位S的情况下,几乎是无穷接近 ± 0 \\pm0 ±0的非常小的数字。故做出此特殊规定。
- E全为1
这时,如果有效数字M全为0,表示 ± \\pm ±无穷大。
E在二进制序列中表示的值是加上127之后的值,如果E是全1的话,单精度的8个bit位的E在没有存储之前的值应该是128。E是指数位,想象一下 2 128 2^{128} 2128是一个多么大的数字?在不考虑符号位S的情况下,几乎是正负无穷大的一个数字。
栗子🌰
下面我们看一道浮点数存储的栗子:
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;
}
✏int n = 9;
因为9是一个正数,原反补相同,故补码为:00000000 00000000 00000000 00001001
按浮点数的存储方式来拆分:
惊奇的发现E为全0?那么就应该按E为全0时的规定办事。
E = 1 − 127 = − 126 E=1-127=-126 E=1−127=−126
M = 0.00000000000000000001001 M = 0.00000000000000000001001 M=0.00000000000000000001001
S = 0 S = 0 S=0
转换为科学计数法: 0.00000000000000000001001 × 2 − 126 0.00000000000000000001001\\times2^{-126} 0.00000000000000000001001×2−126
显然是一个无穷小的数字,而
%f
默认打印的是小数点后六位的数字,故打印出来是以上是关于浮点型在内存中的存储(建议收藏食用)的主要内容,如果未能解决你的问题,请参考以下文章