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

        今天让我们来看看整型的数据和浮点型的数据在内存中是怎么存储的呢

        整型数据在内存中的存储

        整型数据在内存中存储的是二进制的补码

        正数的话也没什么可说的,原码反码补码都相同

        我们来看看负数:

       以-5为例

        原码:10000000 00000000 00000000 00000101

        反码:11111111 11111111 11111111 11111010

        补码:11111111 11111111 11111111 11111011

        负数的反码就是符号位不变,其他位按位取反。负数的补码就是反码+1.

        为什么内存要存补码?

        在计算机系统中,数值一律使用补码的方式来表示和储存。我们使用补码的原因在于,使用补码可以将符号位和数值域统一处理。

        同时,加法和减法也可以使用补码来统一处理,因为CPU中其实只有加法器。

        此外,补码与原码相互转换,它们的运算过程是相同的,不需要额外的硬件电路去进行补码到原码的额外转换;大致情况如图:

        

        我们还是以-5为例

        原码:        10000000 00000000 00000000 00000101

        补码:        11111111 11111111 11111111 11111011

        补码取反: 10000000 00000000 00000000 00000100

        加一:        10000000 00000000 00000000 00000101

        我们通过运算可以看到,结果无误,补码取反加一之后确实可以得到原码。

        其实在我们之前的一篇博客中解释过了大小端存储,我们使用的vs2022使用的就是小端字节序存储方式。

        还是以-5为例

        

        我们通过程序的调试可以发现,在a的地址0x012ff87c中a存储的值为fb ff ff ff,那么我们再来看看-5的补码:

        补码:11111111 11111111 11111111 11111011

        十六进制为:ff ff ff fb

        十六进制数中1111(十进制为15)是f,1011(十进制为11)是b

        小端存储方式是数据的高位存储在高地址,数据的低位存储在低地址,这里也印证了我们之前的结论。        

        了解了整型在内存中的存储,我们再来看看浮点型在内存中是怎么存储的吧

        浮点型数据在内存中的存储

        在了解浮点型存储方式之前,想邀请大家来猜一猜以下的代码输出的值都是多少

        

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;
}

        大家要好好想一想哦

        浮点型存储的标准

        既然这里这样说了,那么我们就了解浮点型与整型在内存中的存储方式肯定是不一样的了,那我们来看看浮点型存储的标准

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

        (-1)^S*M*2^E

        -1^S表示符号位,当S=0,V是正数;当S=1,V为负数。

        M表示有效数字,M表示的值大于等于1,小于2。就是将数字变为科学计数法

        2^E表示指数位

        大家是不是一脸懵逼啊,我刚刚看到的时候也是,给大家举几个例子理解一下

        假设V=5.5

        二进制表示:101.1

        在转换为2进制的时候要注意小数点之后的权重,从小数点第一位开始,往后的权重依次为2^-1,2^-2,2^-3......

        这里我们来看,有效数字M要求是大于等于1,小于2,那么我们这里就需要将101.1的小数点往前移动两位可以达到要求,那么我们这里就变为了1.011*2^2,我们这里是2进制数字,乘的底数就为2,小数点往前移几位,咋们就乘2的多少次方。

        这里我们基本上就解决了,那么我们的V应该怎么写呢

        V=5.5=(-1)^0*1.011*2^2

        S=0(数字为正数)

        M = 1.011(有效数字)

        E = 2

        IEEE 754 规定

        在内存中,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M

        图示:

        

        对于64位的浮点数,最高一位是符号位S,接着的11位是指数E,剩下的52位为指数S。

        

       有效数字M

        有效数字M,我们M的值只能是1~2之间的话,那么我们表示M就可以使用1.xxxxxx的形式,xxxxxx表示小数部分

        IEEE 754 规定,在计算机内部保存M的时候,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。

        比如保存1.01的时候,我们可以直接保存01,等到我们需要读取的时候,再把第一位加上去。我们这样做的目的是,节省一位有效数字。以32位浮点数为例,留给M的只有23位,我们将第一位舍弃之后,就可以保存24位的有效数字

        指数E的复杂情况

        首先我们需要了解的是E的类型是unsigend int类型,它是一个无符号整数,那么这意味着,当E在单精度浮点型里为8位的时候它的取值是0~255,但是我们知道在科学计数法中,E是可以出现负数的,那么我们针对这个问题IEEE 754规定,输入内存时E的真实值必须再加上一个中间数,对于8位E,这个中间数为127,11位的话是1023。

        那么当我们要在内存中存的e为10的时候,我们需要将10+127,存放137进入内存,E=10001001。

        之后指数E从内存中取出还要分3种情况

        E不全为0或E不全为1

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

        例如:

        0.5的二进制表示为0.1,由于规定正数部分必须为1,即将小数点右移一位,则为1.0*2^(-1),其阶码为-1+127=126,表示为:01111110,而尾数部分去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示为

        0 01111110 00000000000000000000000

        E全为0

        这个时候,浮点数的指数e等于1-127或者(1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原成0.xxxxxx的小数。这样是为了表示+-0,以及接近与0的很小的数字。

        E全为1

        这时,如果有效数字M全为0,表示+-无穷大,正负取决于符号位s。        

        现在大家对之前的题有答案了嘛

        我们来看看

        代码运行结果

        

       疑问与下回分解

        在n=9的时候为什么*pFloat的值会是0.000000呢?为什么num的值会那么大呢?为什么在n的值为9.0 的时候*pFloat的值会是9.000000呢?

        写不动喽,我们有很多疑问,大家可以先消化一下今天的知识,我们每天再来为大家详细解释。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/571682.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】Redis

文章目录 [toc]Redis终端操作进入Redis终端Redis服务测试切换仓库 String命令存储字符串普通存储设置存储过期时间批量存储 查询字符串查询单条批量查询 Key命令查询key查询所有根据key首字母查询判断key是否存在查询指定的key对应的value的类型 删除键值对 Hash命令存储hash查…

【HTML】页面引用Vue3和Element-Plus

在现代前端开发中,Vue 3 和 Element Plus 是非常受欢迎的技术。Vue 3 是一个用于构建用户界面的渐进式 JavaScript 框架,而 Element Plus 是一个基于 Vue 3 的组件库,提供了丰富的 UI 组件,帮助开发者快速构建高质量的前端应用。 …

frp 实现 http / tcp 内网穿透(穿透 wordpress )

frp 实现 http / tcp 内网穿透(穿透 wordpress ) 1. 背景简介与软件安装2. 服务端配置2.1 配置文件2.2 wordpress 配置文件2.3 frps 自启动 3.客户端配置3.1 配置文件3.2 frpc 自启动 同步发布在个人笔记frp 实现 http / tcp 内网穿透(穿透 w…

多目标粒子群算法及其MATLAB实现

多目标粒子群优化(Multi-Objective Particle Swarm Optimization, MOPSO)算法是一种基于种群的优化算法,它结合了粒子群优化(Particle Swarm Optimization, PSO)和多目标优化的思想。多目标粒子群(MOPSO&am…

DevOps(八)Jenkins的Maven和Git插件

一、Maven简介 Maven是一个构建生命周期管理和理解工具,用于Java项目。它提供了标准化的构建流程,并简化了从项目编译到文档生成等各种构建方面的管理。 Maven是由Apache软件基金会开发和维护的一个流行的项目管理工具。它的设计目的是简化Java项目的构…

PE结构(二)PE头字段说明

PE头字段 DOS头 PE标记 标准PE头 可选PE头 我们今天分析一下PE头字段中所有重要成员的含义 DOS头 DOS头中我们需要去分析的是如下两个成员: 1.WORD e_magic:MZ标记,用于判断是否为可执行文件,即如果显示4D 5A,…

[2021年最新]国产时序性数据TDenige入门

一、TDenige简介 TDengine:是涛思数据面对高速增长的物联网大数据市场和技术挑战推出的创新性的大数据处理产品,它不依赖任何第三方软件,也不是优化或包装了一个开源的数据库或流式计算产品,而是在吸取众多传统关系型数据库、NoS…

图搜索的经典启发式算法A星(A*、A Star)算法详解

文章目录 1. 引言2. 广度优先搜索3. Dijkstra 算法4. 启发式优先搜索(Heuristic)4.1 贪心最佳优先搜索4.2 A*搜索 1. 引言 在许多场景中,我们常会遇到一类问题,即“找到一个位置到另一个位置的距离最短(用时最少&…

ELK 日志分析系统(二)

一、ELK Kibana 部署 1.1 安装Kibana软件包 #上传软件包 kibana-5.5.1-x86_64.rpm 到/opt目录 cd /opt rpm -ivh kibana-5.5.1-x86_64.rpm 1.2 设置 Kibana 的主配置文件 vim /etc/kibana/kibana.yml --2--取消注释,Kiabana 服务的默认监听端口为5601 server.po…

ubuntu 24.04 beta server NAT模式上网设置

在Ubuntu 24.04 Beta上设置网络通常涉及使用命令行工具。以下是设置静态IP地址和动态IP地址的步骤: 动态IP设置: 查找你的网络接口名称: ip a ens37是我NAT模型的一张网卡,此时是没有ip的。 下面介绍如何NAT模式下添加DHCP动态…

Maven多模块快速升级超好用Idea插件-MPVP

功能:多模块maven项目快速升级指定版本插件,并提供预览和相关升级模块日志能力。 可快速进行版本升级,进行部署到Maven仓库。 安装: 可在idea插件中心进行安装 / 下载资源拖动安装 MPVP(Maven) - IntelliJ IDEs Plugin | Marke…

node.js 解析post请求 方法一

前提:依旧以前面发的node.js服务器动态资源处理代码 具体见 http://t.csdnimg.cn/TSNW9为模板,在这基础上进行修改。与动态资源处理代码不同的是,这次的用户信息我们借用表单来实现。post请求解析来获取和展示用户表单填写信息 1》代码难点&…

快速新建springboot项目

一、初始化 1.打开IDEA,在Spring initializer这里按照下图项目进行配置。注意:如果jdk是1.8建议将Server URL这里替换为图中的阿里云服务器,否则容易找不到对应的java8,然后点击next 2.在这里提前配置一些需要使用的依赖&#xf…

Linux上部署Jupyter notebook

安装jupyter notebook pip install notebook #或者 conda install notebook配置 jupyter notebook --generate-config## The IP address the notebook server will listen on. # Default: localhost # 设置可以访问的ip, 默认是localhost, 将其改为 * c.NotebookApp.ip *#…

CMakeLists.txt中如何添加编译选项?

1. 引子 编译器有多种可供选择,如g、c、clang等,如下以c作为示例。 2. 使用CMAKE_CXX_FLAGS添加编译选项 在Makefile中可能用类似如下的指令来添加编译选项: /usr/bin/c -Wall -Wextra -Wno-sign-compare -Wno-unused-variable -Wno-unuse…

LLM大语言模型(十三):ChatGLM3-6B兼容Langchain的Function Call的一步一步的详细转换过程记录

# LangChain:原始prompt System: Respond to the human as helpfully and accurately as possible. You have access to the following tools: Calculator: Useful for when you need to calculate math problems, args: {\calculation\: {\description\: \calcul…

云安全防御篇:如何识别并做好服务器DDoS防护?

伴随着全球互联网业务和云计算的快速发展,作为一种破坏力巨大的攻击方式,DDoS攻击正以超出服务器承受能力的流量淹没网站,导致服务器宕机、企业营业额下跌,甚至企业品牌形象受损。越是面对复杂的攻击,就需要性能更强的…

linux安装nacos(单机简易版本)

1. 查看Java版本,必须有jdk支持 2. 下载安装包,解压 下载地址: https://github.com/alibaba/Nacos/releases 2.1 上传到 /opt文件夹 2.2使用解压命令 tar -zxvf nacos-server-2.2.1.tar.gz 2.3 解压后产生文件夹 3. 配置 3.1 修改配置&…

牛客NC98 判断t1树中是否有与t2树完全相同的子树【simple 深度优先dfs C++/Java/Go/PHP】

题目 题目链接: https://www.nowcoder.com/practice/4eaccec5ee8f4fe8a4309463b807a542 思路 深度优先搜索暴力匹配 思路和算法这是一种最朴素的方法——深度优先搜索枚举 s 中的每一个节点,判断这个点的子树是否和 t 相等。如何判断一个节点的子树是否…

zabbix6.4告警配置(短信告警和邮件告警),脚本触发

目录 一、前提二、告警配置1.邮件告警脚本配置2.短信告警脚本配置3.zabbix添加报警媒介4.zabbix创建动作4.给用户添加报警媒介 一、前提 已经搭建好zabbix-server 在需要监控的mysql服务器上安装zabbix-agent2 上述安装步骤参考我的上篇文章:通过docker容器安装za…