探索C语言:整数和浮点数在内存中存储的差异

一、整数在内存中的存储

整数的二进制表示方法有:原码、反码、补码

  • 原码:直接将原数据按照正负数转换为二进制后的序列,序列的最高位是符号位(0代表正数,1代表负数)。
  • 反码:将原码除了符号位不变外,其它位全部按位取反,就是0变为1,1变为0。
  • 补码:在反码的基础上 +1。

另外要注意,正数的原码、反码和补码都是相同的,因此只有遇到负数的时候我们才会去刻意地求补码

🧐为什么要搞出这么多种码?

原因是因为CPU只有加法器,也就是说CPU只能处理数据间相加。

如果只有原码一种的话,我们看这两个例子,假设我们要计算1 + 1等于多少,CPU根据它们的原码进行加法(00000001 + 00000001 = 00000010),结果为2,正确!假设是1 - 1 = 1 + (-1),同样CPU把它们的原码相加(00000001 + 10000001 = 10000010),结果为-2,出现错误!

我们知道正数的符号位为0,所以不会干扰到计算的结果,为了解决CPU无法执行减法的情况,聪明的祖师爷就引入了补码这一概念。后来,整形数据存放在内存一律就采用了补码。
对于正数来说,它的原、反、补都相同,用谁存都一样;对于负数来说,同样是计算1 + (-1),先把-1的原码(10000001)转换反码(11111110),再转换成补码(11111111)后,把(00000001 + 11111111 = 00000000),得到的结果就是正确的了。

二、浮点数在内存中的存储

浮点数在内存中的存储可以查看国际标准IEEE754文件


1、IEE754标准

20世纪80年代左右,计算机厂商们还是各自为战,,每家都在设计自己的浮点数存储规则, 彼此之间并不兼容。 直到1985年, 电气和电子工程协会制定的IEEE754标准问世, 浮点数的存储问题才有了一个通用的工业标准。

IEEE754标准提供了如何在计算机内存中,以二进制的方式存储十进制浮点数的具体标准,目前包括 Java,C,C++等在内的许多编程语言在实现浮点数时, 都遵循IEEE754标准。

根据IEEE754规定,任何一个二进制浮点数V都可以表示成:
在这里插入图片描述

浮点数分为float单精度浮点数(或32位浮点数)double双精度浮点型(或64位浮点数)

IEEE754规定

  • 对于32位的浮点数,最高的一位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。
  • 对于64位的浮点数,最高的一位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M。
    在这里插入图片描述

2、深入学习浮点数在内存中的存储规则

接下来以32位的浮点数为例,去研究浮点数在内存中的存储规则!
想要存储一个32位的浮点数,在内存中就要占用32个比特位(或者说32个小格子),这32个比特位被划分成3部分,用途各不相同。如下图:
在这里插入图片描述

  • sign:符号位,即图中蓝色部分。
  • biased exponent: 偏移后的指数位, 即图中绿色部分。
  • frantion:有效数字位,即图中红色部分。

例如:10.5在内存中存储的二进制数位是:

  |          |
0 | 10000010 | 01010000000000000000000
  |          |
32个比特位被划分成3部分存储!

那么该怎样把十进制的10.5转换成0 10000010 01010000000000000000000存入内存中呢?接下来带大家一步一步去转换!

2.1、符号位: sign

在这里插入图片描述
符号位S,占据最高的第31位,用来表示该浮点数是正数还是负数,0表示正数,1表示负数。
例如:浮点数10.5,它为正数,那么它在内存中存储的最高二进制位(sign)为0,表示正数


2.2、偏移后的指数位: biased exponent

在这里插入图片描述
指数位E是用来存放以2为底的指数的,而且E是一个无符号整数(unsighed int),我们知道32位的指数位E位8比特位,那它的取值范围为0~255,E为11比特,则取值范围为0-2047。
但是,在有效数位中我们采用的是科学计数法,E可以为负数;(例如:0.1 用科学计数法变成 1.0x2^-1,其中 1.0 是有效数位M,-1 就是指数位 E。)因此浮点数型的指数位都有一个固定的中间值,也叫偏移量,用于使 指数 + 偏移量 = 一个非负整数,这样就解决了指数位出现负数的情况了。

IEEE754规定:在32位单精度浮点型中,偏移量是127;在64位双精度浮点型中,偏移量是1023。
(例如:在32位中,当我们计算出的指数是-20,那么就把 -20 + 127 = 107,此时得到的指数就变成了107,而不是 -20 了,然后再把指数107转换成二进制数 0110 1011,存放入指数位E中;当指数为20,同样的道理,把 20 + 127 = 147,此时的指数就变成了147,而不是20了,然后同样把147转换成二进制数 1001 0011,存放入指数位E中。)

看完这个例子后,我们可能会有一个疑问,就是为啥要搞这么复杂的规则出来啊😭…其实这是很有必要的,上文提到32位单精度浮点型的指数位就只有8个比特大小,如果来要留出一个比特位来判定正负数,那存储利用率将大打折扣,因此,干脆就制定一个规则(+偏移量),使得不管是正数还是负数,都通过一个统一的规则转化一下,就像原反补码一样。


2.3、有效数位:M(fraction)

在这里插入图片描述
32位的浮点数(单精度浮点数 / float类型浮点数)需要使用23比特位来存储有效数字位M,64位浮点数(双精度浮点数 / double类型浮点数)需要52比特位来存储有效数字M。

以10.5为例,首先把十进制的10.5转换成二进制:1010.1,然后把1010.1按照科学计数法来写,就得到了 1.0101 x 2^3,其中的 3 就是上面说到的指数位E,1.0101 就是有效数位M
但是,得到的 1.0101 并不会直接存放到内存中,因为还要对它进行规范化处理。

①.隐藏高位1
我们把十进制的10.5的二进制数 1010.1 是按照科学计数法来写成1.0101的,而二进制只有0和1,因此我们可以发现小数点前的第一位永远都是 1,再看上图可知,32位浮点数的有效数位只有23比特位,为了提高内存利用率,第一位的1可以被舍弃,这样就可以节约1比特的空间了,所以对于1.0101来说,我们只需保存小数后面的0101就行了

②.低位补0
当把高位的1舍弃后,得到了 0101 ,但是 0101(不足23位),因此要低位补0,补够23位变为 0101 0000 0000 0000 0000 000


完结

浮点数10.5:

符号位S:0
偏移后的指数位E:1000 0010
有效数位M:0101 0000 0000 0000 0000 000

然后我们再把这三部分按照顺序存放进内存,就是 0 10000010 01010000000000000000000

下面使用计算机验证结果是准确的!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白菜不空心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值