浮点数在内存中的存储

简介: 浮点数在内存中的存储

浮点数在内存中的存储详解

我们知道, 计算机内部实际上只能存储或识别二进制。

在计算机中, 我们日常所使用的文档, 图片, 数字等, 在储存时, 实际上都要以二进制的形式存放在内存或硬盘中, 内存或硬盘就好像是一个被划分为许多小格子的容器, 其中每个小格子都只能盛放0或1。我们日常使用的 浮点数 也不例外, 最终也要被存储到这样的二进制小格子中。(来源于知乎)

对于整形来说:数据存放内存中其实存放的是补码。

那么,对于浮点数来说,在内存中是如何存储的呢?

首先,先来说一下浮点型数字的二进制怎么表示:

例如,5.5

前面的5为整数,表示为0101

后面的0.5等于2^(-1),二进制位0.1

故5.5的二进制为0101.1

下面,我给出一段代码,大家可以先自己思考以下输出的结果

#include <stdio.h>
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;
 }

思考完了吧!

下面请看结果:

相信大家可能都会对这个结果产生疑问,咋就是和我想得不一样呢?(本人真爱粉,不要黑我了啊哈哈哈哈)

各位莫急,听我说!

上⾯的代码中, num 和 *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别这么⼤?要理解这个结果,⼀定要搞懂浮点数在计算机内部的表⽰⽅法。

*根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V = (−1)^S M ∗ 2^E
• (−1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
• M 表⽰有效数字,M是⼤于等于1,⼩于2的
• 2^E 表⽰指数位

例如:一个十进制数字5

二进制为 101.0 ,可以表示为 1.01×2^2

S=0 M=1.01 E=2

IEEE 754规定:

对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

下面用图来理解以下上述的IEEE 754规定

(图为32位)

(图为64位)

上面的IEEE 754 规定中我们提到,M的值是属于[1,2)(1到2的左闭右开区间),所以,M的值的小数点前的数只有可能是1,所以在存储的时候,M的表现形式就是" 1.XXXXXXX "默认就把1给省略了。

例如:保存1.01,保存的就只有01,小数点前的1就会省略,读取时把1加上去就可以了

这样就会节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。

接下来就到了指数E的讲解了,这个点比较重要,同时也比较复杂。

⾸先,E为⼀个⽆符号整数(unsigned int)

这意味着,如果E为8位,它的取值范围为0~ 255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的

例如:数字0.5,二进制为0.1,存储为浮点型,但是规定了M大于等于1,所以将小数点右移一位,他的存储形式就是(-1)^ 0 * 1.0*2^(-1),M中的1可以省略,故存为0,转换为23个0,E的值为-1,加上中间值127等于126,存为 01111 1110,存储如下图

所以IEEE 754规定,存⼊内存时E的真实值必须再加上这个指定的中间数,32位的条件下这个中间数就取为127;64位的条件下,这个中间数就取为1023。

例如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001

保存如下

此外,指数E还有一个重点,不能存储为全0或者全1!

废话不多说,以32位举例说明吧

例如,如果E存储为全0的话,就是说E加上中间数127后的二进制为0000 0000,大家可以想到指数E是-127,几乎趋近于0。

而存储全为1的话,就是指数E就是128,就会趋近于无穷大了

下面,我们带着知识点回到开头的练习,对其进行解析

首先,n为9,他的二进制为

0000 0000 0000 0000 0000 0000 0000 1001

因为9是正数,所以源码等于反码等于补码,故存储在内存中就是上述二进制序列

当9被以浮点型数字拆分,就为以下序列:

0 0000 0000 000 0000 0000 0000 0000 1001
//浮点数V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

这个数趋近于零,故打印浮点型为0.000000

下面看第二部分,9的二进制为1001,v=(-1)^ 0*1.001 *2^3

E=3,E+127=130,M为1.001,省略小数点前的1,将001存入内存,后面补二十个零

E的二进制为

1000 0010

M的二进制位

001 0000 0000 0000 0000 0000 0000

二进制序列位S+E+M

将浮点型数字9.0以存入内存,序列为

0 10000010 001 0000 0000 0000 0000 0000

当9以整形输出,因为为正数,所以直接将此二进制序列看作源码,用windows计算机算出十进制数值为1091567616

大家有空的话可以自己尝试着联系一下。

好了,阿豪今天的分享就到这了,点个关注不迷路哦!

相关文章
|
1月前
|
存储 C++
看完就等于拿捏浮点数在内存中的储存了
看完就等于拿捏浮点数在内存中的储存了
43 2
看完就等于拿捏浮点数在内存中的储存了
|
16天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
31 1
|
20天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
25天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
30天前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
37 4
|
28天前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
50 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
1月前
|
存储 机器学习/深度学习 人工智能
数据在内存中的存储
数据在内存中的存储
|
30天前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
1月前
|
存储
整型在内存中的存储
本文详细解释了计算机中整型数据的三种二进制表示方法:原码、反码和补码,并展示了如何将正数和负数的原码转换为反码和补码。
35 0
|
3月前
|
存储 监控 Docker
如何限制docker使用的cpu,内存,存储
如何限制docker使用的cpu,内存,存储