浮点型在内存中的存储(建议收藏食用)

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. ( − 1 ) S (-1)^S (1)S​​​​表示符号位,当 S = 0 S=0 S=0 V V V为正数;当 S = 1 S=1 S=1 V V V​为负数。
  2. M M M​​​表示有效数字,大于等于1,小于2。( 1 ⩽ M < 2 1\\leqslant M < 2 1M<2​​)
  3. 2 E 2^E 2E​​​表示指数位。

举栗子🌰

🌰1: 十进制的5.5转换为二进制

  • 5.5转换为二进制为:101.1
  1. 小数点前的5转换为二进制为:101( 2 2 + 2 0 = 5 2^2+2^0=5 22+20=5
  2. 小数点后的5转换为二进制为:1( 2 − 1 = 1 2 1 = 0.5 2^{-1}=\\frac{1}{2^1}=0.5 21=211=0.5
  3. 改为二进制的科学计数法形式: 1.011 × 2 2 1.011\\times2^2 1.011×22
  4. 改为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. 改为二进制的科学计数法形式: 1.001 × 2 3 1.001\\times2^3 1.001×23
  2. 改为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 1M<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;
  1. 转化为二进制:101.1(转换为二进制的过程
  2. 改为科学计数法: 1.011 × 2 2 1.011\\times2^2 1.011×22​​
  3. 改为IEEE 754标准公式形式: ( − 1 ) 0 × 1.011 × 2 2 (-1)^0\\times1.011\\times2^2 (1)0×1.011×22
  4. S = 0 ; M = 1.011 ; E = 2 S=0;M=1.011;E=2 S=0;M=1.011;E=2
  5. 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从内存中取出将会分为三种情况👮‍♀️:

  1. E不全为0或不全为1

这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。

例如下面这一个二进制序列:

E = 126 − 127 = − 1 E = 126 - 127=-1 E=126127=1

M = 0 M = 0 M=0

转化为科学计数法: 0.0 × 2 − 1 0.0\\times2^{-1} 0.0×21

转化为二进制则为:0.1(则图示二进制序列的值为0.5)

  1. 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}} 2127=21271​​​​是一个多么小的数字鸭?​在不考虑符号位S的情况下,几乎是无穷接近 ± 0 \\pm0 ±0​​的非常小的数字。故做出此特殊规定。

  1. 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=1127=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×2126

显然是一个无穷小的数字,而%f默认打印的是小数点后六位的数字,故打印出来是

以上是关于浮点型在内存中的存储(建议收藏食用)的主要内容,如果未能解决你的问题,请参考以下文章

深度剖析数据在内存中的存储之浮点型在内存中的存储

C语言学习 -- 整型与浮点型在内存中的存储

[ C语言 ]一篇带你了解浮点型在内存中的存储

请问浮点型数据在计算机是怎么存储的

C语言整型在内存中的存储

浮点数与整型在内存中的存储比较