当前位置: 首页 > news >正文

浮点数在内存中的存储详解(超详细)

211da4f687d9491f828be3be8f1d8e6a.png

目录

1. 浮点数存储规则

2. IEEE754规定:

3. 关于M的说明:

4. 关于E的说明:

5. 关于S的说明:

6.浮点数从内存中取出(三种情况)

 情况1:E不全为0或不全为1

 情况2:E全为0

 情况3:E全为1


小心!VS2022不可直接接触,否则!没这个必要,方源面色淡然一把抓住!顷刻炼化! 


1. 浮点数存储规则

大家都知道整型数据是以补码的方式存放在内存中。以下几个概念是需要知道的:

原码,补码,反码都是以二进制形式表示的。
正整数的原码,反码,补码都相同。
负整数的补码=反码+1=原码的符号位不变,数值位按位取反。
但是浮点数不同,浮点数有着一套自己的存储规则。
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

  • (-1)^S * M * 2^E
  • (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
  • M表示有效数字,大于等于1,小于2。
  • 2^E表示指数位。
  • E是一个无符号整数。

这里需要记住S,M,E分别代表的是什么

简述:S用于判断正负号,M表示有效数字,E与小数点相关


2. IEEE754规定:

 对于32位的浮点数,最高一位为S,接着的8位是指数E,剩下的23位为有效数字M。

2531fdd30fda42e8af2213844fd0dfb5.jpeg
对于64位双精度数,最高一位为S,接着的11位是指数E,剩下的52位为有效数字M。

3df9bb3d622e4c7aa8cc8fef7db3f745.jpeg


3. 关于M的说明:

无论是单精度float还是双精度double,它们的有效数字M可以写成1.xxxx的形式,但通常1都会省略掉,系统默认为1,这样可以节省一格bit位,比如存放二进制1.01时,M中只会存放01,整数部位1会省略不写


4. 关于E的说明:

E为一个无符号整数(unsigned int),因此如果E为8位bit,它的取值为0-255,如果E为11位bit,它的取值为0-2047

IEEE 754规定,存入内存时,E的真实值必须再加上一个中间数,这个中间数在8位的E中是127,在11位的E中是1023,(其实就是最大取值的一半),比如2的10次方的E,E此时为10,所以保存成32位(float)浮点数时,必须保存成10+127 =137的二进制,即10001001


5. 关于S的说明:

S可以决定小数是正数还是负数,如果存储的是正数,S为0,如果存储的是负数,S为1


我们举出两个例子,来讲解浮点数在内存中的存储:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{float a = 5.5f;/*S = 0 5.5 的二进制为 101.1 ,整数部位1省略不写M = 011因为101.1 = 1.011 * 10的2次方,所以E  = 2因为是float型存储,所以E要在真实值上加127,即129,129的无符号二进制为1000 0001,所以E的存储方式为1000 0001[0]  [1][0][0][0][0][0][0][1]   [0][1][1][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]S			E					M	*/float b = 0.5f;/*S = 0;0.5 的二进制为 0.1因为二进制形式规定第一位必须为1,所以可以写成1.0 * 10的-1次方,因此 E = -1,M = 0E需要在真实值上+127,即126,,126的无符号二进制为0111 1110,所以E的存储方式为 0111 1110低地址[0]  [0][1][1][1][1][1][1][0]   [0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]高地址*/
}	

6.浮点数从内存中取出(三种情况)

我们学习了浮点数的存储,那浮点数从内存中取出打印出来又是如何操作的呢?

就像我们知道,整数存储的是补码,使用printf打印出来的是原码


 情况1:E不全为0或不全为1

当E不全为0或不全为1时,浮点数在从内存中取出时会将E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1

详细讲解如下:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{float a = 5.5f;/*低地址[0]  [1][0][0][0][0][0][0][1]   [0][1][1][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]高地址S			E							M	取出方式:E此时为小端存储,无符号整数E表示129,取出时用129-127 得到E的真实值 2 ,再将有效数字M前加上第一位的1过程 :1.011 向右移动 E 个小数点,得到最后结果101.1相当于二进制原码为101.1*/float b = 0.5f;/*低地址[0]  [0][1][1][1][1][1][1][0]   [0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]高地址取出方式:E此时无符号整数表示为126,需要减去127,得到E的真实值-1,再将有效数字M前加上第一位的1,过程: 1.0 向右移动 E 个小数点,表示0.1相当于二进制原码为0.1*/
}	

 情况2:E全为0

 如果E全为0,E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原成0.xxxxxxx的小数

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int main()
{/*低地址[0]  [0][0][0][0][0][0][0][0]   [0][0][1][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]高地址S			E							M	如果浮点数此时这样存储,想要推出它原本的二进制数E = 1-127 得到真实值 -126M不再加1,而是还原成0.xxxx,所以M此时为0.001相当于原码为 0.001的小数点向右移动-126位是一个极其接近0的小数*/
}	

 情况3:E全为1

当E全为1时,表示特殊值。如果M全为0,表示±无穷大(正负取决于符号s),如果M不全为0,表示这不是一个数(NaN)。

8fdd48caf53e46a897fd8a5554dbb454.png


http://www.mrgr.cn/news/27928.html

相关文章:

  • Golang | Leetcode Golang题解之第565题数组嵌套
  • Python进程间通讯大揭秘:原理深度剖析与实战案例分享
  • 电商系统开发:Spring Boot框架实战
  • 51单片机应用开发(进阶)---定时器应用(电子时钟)
  • 基本定时器---内/外部时钟中断
  • 用OMS进行 OceanBase 租户间数据迁移的测评
  • JavaScript高级——循环遍历加监听
  • PointNet++改进策略 :模块改进 | PointNetXt ,利用训练测量大幅提升PointNet模型性能
  • 如何迈向IT行业的成功之路
  • 智能机巢+无人机:自动化巡检技术详解
  • redisson实现分布式锁
  • 基于yolov5的混凝土缺陷检测系统python源码+onnx模型+评估指标曲线+精美GUI界面
  • 文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑生产环节内特性的工业负荷调峰优化运行及二次调频能力评估 》
  • 建筑裂缝检测图像ai模型训练数据集
  • 利用Python在Win10环境下实现拨号上网
  • PHP环境搭建
  • 解码 OpenAI 的 o1 系列大型语言模型
  • Linux查看自己公网IP
  • java 网络编程URL与URLConnection的使用
  • AIGC实战——多模态模型Flamingo
  • 使用EXPORT_SYMBOL
  • Python编程 - 异常处理与文件读写
  • 拒绝低效!开发者必备AI工具助你事半功倍!
  • Sitecore 定时任务使用介绍
  • python多线程程序设计 之一
  • 【Python爬虫系列】_022.异步文件操作aiofiles