❤浮点型在内存中的存储【建议收藏食用】❤

浮点型在内存中的存储

概念📚

整数型表示大小范围可在<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

在这里插入图片描述
而这段十六进制的数在内存中会被存储为:0000B040
这就涉及到了多字节数据在内存中的存储,也就是所谓的字节序的问题。
(本篇文章意在详解浮点型在内存中的存储,字节序详解请跳转笔者另一篇文章)

取🎈

指数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默认打印的是小数点后六位的数字,故打印出来是:0.000000。

*pFloat = 9.0;9.0是一个单精度浮点类型的数字:

先转化为二进制:1001.0

科学计数法: 1.001 × 2 3 1.001\times2^3 1.001×23

E = 3 + 127 = 130 E=3+127=130 E=3+127=130

M = 1.001 M = 1.001 M=1.001

S = 0 S = 0 S=0

E的二进制序列为:10000010

M的二进制序列为:001

在内存中的存储:

在这里插入图片描述

%d的形式打印显然就是打印这串二进制序列对应的十进制的整数值。而这串二进制序列符号位为0,也就是原反补是相同的。故打印出来的结果是:1091567616( 2 30 + 2 24 + 2 20 = 1091567616 2^{30}+2^{24}+2^{20}=1091567616 230+224+220=1091567616

(全剧终)感谢食用!

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值