数据的存储(类型的提升)

       在操作负中,我们讲解过整形提升运算符(详情请看写文章-CSDN创作中心操作符(原码反码补码)-CSDN博客写文章-CSDN创作中心),知道CPU都是基于整形运算的,而且每个类型都有其最大存储的整数。

目录

字符型在内存中的存储: 

 浮点数在内存中的存储:

 E全为0时:

E全为1时: 

举例:

总结:

字符型在内存中的存储: 

       比如一个char类型,我们知道在内存中占据1个字节,而且分为有符号和无符号类型。当是有符号的时候,最高位被符号位占据,所以一个字节能存储的最大整形就是2^7-1 = 127;最小整数是 -128。这个-128即0111 1111 + 1得到的。

       我们定义char类型补码中存储的10000000是-128。

int main()
{
	char a = -128;
	//先整形提升,保留符号位
	//之后打印无符号数
	printf("%u\n", a);
	return 0;
}

        前面的位按照符号位补全。C语言中,整形算数运算符总是至少以缺省整形类型的精度来进行的,为了获取这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为整形提升。

       通用CPU是难以直接实现两个8比特字节直接相加运算的。所以表达式中各种长度可能小于int长度的整形值,都必须先转换为int或unsigned int,然后才能送入CPU执行运算。 

       我们再举一个例子:

int main() 
{
	//char类型取值范围是:-128~127
	//char是占用1个字节的,1个字节8个bit位
	char c1 = 125;
	//00000000 00000000 00000000 01111101
	//发生截断
	//01111101 - c1

	char c2 = 10;
	//00000000 00000000 00000000 00001010
	//00001010 - c2

	char c3 = c1 + c2;
	//00000000 00000000 00000000 01111101
	//00000000 00000000 00000000 00001010
	//00000000 00000000 00000000 10000111
	//10000111 - c3
	//提升
	//11111111 11111111 11111111 10000111 - 补码
	//11111111 11111111 11111111 10000110 - 反码
	//10000000 00000000 00000000 01111001 - 原码
	//-121
	printf("%d\n", c3);
	//%d 打印有符号整数
	//%u 打印十进制无符号整数
	return 0;
}

       我们再举一个例子:

int main()
{
	char a = -1;
	//10000000 00000000 00000000 00000001
	//11111111 11111111 11111111 11111110
	//11111111 11111111 11111111 11111111
	//存储在a中发生截断
	//11111111 - a
	//11111111 11111111 11111111 11111111 - 提升
	//10000000 00000000 00000000 00000000
	//10000000 00000000 00000000 00000001
	signed char b = -1;
	//11111111 - b
	unsigned char c = -1;
	//11111111 - c
	//无符号整形提升,最高位补0
	//00000000 00000000 00000000 1111111
	printf("a = %d, b = %d, c = %d\n", a, b, c);
	//%d - 十进制的形式打印有符号的整形
	return 0;
}

       C语言规定char类型默认是否带有正负号,有当前系统决定。整形提升时,最高位默认为符号位,也是说不够32位,前面就补上符号位。

int main()
{
	char a = -128;
    char b = 128;//和上面在内存中的存储一样
	//此时char最大存127,再打二进制就加相差多少的数
	//01111111+1=10000000
	//打印无符号的数就先整形提升之后打印
	printf("%u\n", a);
	return 0;
}

        

       我们再来看一个例子:

int main()
{
	char a[1000];
	//-128~127
	//-1 -2 -3 ... -128 127 126 125 ... 5 4 3 2 1 0 -1 -2 ... -128 127 5 4 3 2 1
	//128 + 127 = 255
	int i = 0;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d\n", strlen(a));//求字符串长度找的是\0,\0的ASCII码值是0,其实找的就是0
	//255
	return 0;
}

 总结:对于有符号的char我们可以看成一个圆。

总结: 

        其实每个类型都会有这样的一个循环,我们学习内存的存储是为了从底层理解,这样即使出现很奇怪的数字也可以理解是什么原因。

 浮点数在内存中的存储:

       为什么有双精度浮点数和单精度浮点数?难道只是内存占据大小不一样吗?

IEEE754规定:

       根据国际标准IEEE(电子和电子工程协会)754,任意一个二进制浮点数v可以表示成以下形式:(-1)^S*M*2^E。

  • (-1)^S表示符号位,当s=0,v为正数;当s=1,v为负数。

  • M表示有效数字,大于等于1,小于2。

  • 2^E表示指数位。(如取9)指数位就是小数点向前移动了3位,所以E为3。

       IEEE 754规定:对于32位的浮点数,最高的一位是符号位S,接着的8位是指数E,剩下的23位为有效数字M(float)。

       对于64位的双精度浮点数,最高的一位是符号位S,接着的11位是指数E,剩下的52位为有效数字M(double)。 

       这意味着,如果E为8位,他的取值范围为0~255;如果E为11位,它的取值范围为0~2047,但是我们知道,科学计数法中E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如2^10的E是10,所以保存32位浮点数时,必须保存成10+127=137,及10001001。 

       对于进制的转换,可以去看这篇文章进制的转换-CSDN博客。

       既然M是大于1小于2的,那么第一位肯定是1,以至于我们在保存数据时,是不是就可以把第一位的1省略?确实是这样。

       IEEE 754规定:在计算机内部保存M时,默认第一位数总是1,因此可以被舍去,只保存后面的部分。如保存1.01时,有效位第一个不计入内存,默认是1,等到读取时,再把第一位的1加上去。这样做的目的是节省一位有效数字。以32位单精度浮点数为例,留给M只有23位,将第一位的1舍去后,就等于可以保存24位有效数字。

int main()
{
	float f = 5.5;
	//5.5
	//101.1二进制
	//(-1)*0*1.011*2^2
	//S=0
	//M=1.011
	//E=2
        //之后E加上127为129
	//0 10000001 01100000000000000000000

	//0100 0000 1011 0000 0000 0000 0000 0000
	//在内存中是0x40b00000
	printf("%lf", f);
	return 0;
}

 

        E在计入内存时,加上了127,在读取时就减去127得到真实值;M也是计入内存时前面去掉了1,在读取时(就是带入公式计算时)前面就加上了1。

 E全为0时:

       这时,读取时,浮点数的指数E就等于1-127(或者1-1023)就等于真实值,有效数字M前不再加上1,而是还原为0.xxxx的小数。这样是为了表示+-0,或者无限接近于0的数。

       此时的数字没有意思,我们不做讨论。

E全为1时: 

       这时直接就是无穷大,不讨论。

举例:

        我们举例来看浮点类型在内存中的存储:

int main()
{
	int n = 9;
	//00000000000000000000000000001001-补码
	float* pfloat = (float*)&n;
	printf("n值为%d\n", n);
	printf("*pfloat值为%f\n", *pfloat);
	//0 00000000 00000000000000000001001
	//因为E为全0所以
	//(-1)^0*0.00000000000000000001001*2^-126
	//趋近于0
	*pfloat = 9.0;
	//1001.0
	//1.001*2^3
	//(-1)^0*1.001*2^3
	//0 10000010 00100000000000000000000
	//内存中存的是
	//打印的是整形,所以很大
	printf("n值为%d\n", n);
	printf("*pfloat值为%f\n", *pfloat);
	return 0;
}

 

总结:

       double类型的精度比float精度更高。

       因为对于小数,有时候会一直乘二进制拼凑成其十进制的小数,可能会超出M的极限,所以会近似取值,就是对于有些小数无法精确保存。

       所以两个浮点数比较大小时,直接使用 == 可能存在问题 

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

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

相关文章

32.768KHz时钟RTC晶振精度PPM值及频差计算

一个数字电路就像一所城市的交通&#xff0c;晶振的作用就是十字路口的信号灯&#xff0c;因此晶振的品质及其电路应用尤其关键。数字电路又像生命体&#xff0c;它的运行就像人身体里的血液流通&#xff0c;它不是由单一的某个器件或器件单元构成&#xff0c;而是由多个器件及…

【数据结构 — 排序 — 交换排序】

数据结构 — 排序 — 交换排序 一.交换排序1.基本思想2.冒泡排序2.1.算法讲解2.2.代码实现2.2.1.函数定义2.2.2.算法接口实现2.2.3.测试代码实现2.2.4.测试展示 3.快速排序3.1.算法讲解3.2.各大算法分别单独实现3.2.1快速排序hoare版本3.2.2.快速排序hoare改进版三数取中选key法…

基于OpenCV的流水线包装箱检测计数应用(附源码)

导 读 本文主要介绍基于OpenCV的流水线包装箱检测计数应用,并给出源码。 资源下载 完整代码和视频下载地址: https://github.com/freedomwebtech/rpi4-conveyor-belt-boxces-counter 核心代码如下(cboxtest.py): import cv2import numpy as npfrom tracker import*cap=c…

class067 二维动态规划【算法】

class067 二维动态规划 code1 64. 最小路径和 // 最小路径和 // 给定一个包含非负整数的 m x n 网格 grid // 请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 // 说明&#xff1a;每次只能向下或者向右移动一步。 // 测试链接 : https://leetcode…

Fortran读取netcdf文件/WRF中的文件读取

一直很好奇WRF到底如何通过netcdf库读取netcdf文件&#xff0c;正巧有个机会&#xff0c;试了下fortran读取nc文件&#xff0c;总结一下。 netcdf库 Fortran读取nc文件需要依赖netcdf外部库。安装该库以后&#xff0c;会有专门写给ffortran函数声明的头文件&#xff1a;netcd…

RC522(RFID射频模块)读卡ID的简单应用

文章目录 一、RFID是什么&#xff1f;二、RC522模块三、使用步骤1.硬件1.硬件连接2.引脚定义 2.软件1.初始化配置代码如下&#xff08;示例&#xff09;&#xff1a;2.引脚配置代码如下&#xff08;示例&#xff09;&#xff1a;3.模块复位代码如下&#xff08;示例&#xff09…

【工具】JS|浏览器脚本6分钟极速入门 · 开发一个限制自己刷b站的脚本

这张图花里胡哨的是让AI生成的&#xff0c;我觉得怪可爱的&#xff0c;就直接作为封面了。 这篇文章中会开发一个JS脚本&#xff0c;这是一个用来限制b站网页版功能的脚本&#xff0c;避免刷b站的时间过长。功能如下&#xff1a; 除了搜索、视频页、私信页之外的任何页都会被重…

Vue3:修改下拉框el-select的样式

问题 在Vue3项目中&#xff0c;使用了elemen-plus的下拉框&#xff0c;但是使用深度修改下拉框的样式&#xff08;比如下拉框的背景颜色&#xff09;一直不生效 解决 给下拉框框添加 popper-class属性&#xff0c;属性名根据需求取&#xff0c;比如这里取的是"selectSt…

【Docker】进阶之路:(一)容器技术发展史

【Docker】进阶之路&#xff1a;&#xff08;一&#xff09;容器技术发展史 什么是容器为什么需要容器容器技术的发展历程Docker容器是如何工作的 什么是容器 容器作为一种先进的虚拟化技术&#xff0c;已然成为了云原生时代软件开发和运维的标准基础设施。在了解容器技术之前…

【LeetCode刷题】-- 137.只出现一次的数字II

137.只出现一次的数字II class Solution {public int singleNumber(int[] nums) {Map<Integer,Integer> map new HashMap<>();for(int num : nums){Integer count map.get(num);if(count null){count 1;}else{count;}map.put(num,count);}for(Integer val:map.…

2023年安全员-B证证考试题库及安全员-B证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年安全员-B证证考试题库及安全员-B证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的…

LeetCode---374周赛

题目列表 2951. 找出峰值 2952. 需要添加的硬币的最小数量 2953. 统计完全子字符串 2954. 统计感冒序列的数目 一、找到峰值 这个简单的模拟&#xff0c;代码如下 class Solution { public:vector<int> findPeaks(vector<int>& mountain) {int nmountain…

【附源码】完整版,Python+Selenium+Pytest+POM自动化测试框架封装

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试框架简介 …

[每周一更]-(第76期):Go源码阅读与分析的方式

读源码可以深层理解Go的编写方式&#xff0c;理解作者们的思维方式&#xff1b;也有助于对Go语法用法深刻的理解&#xff0c;我们从这一篇说一下如何读源码&#xff0c;从哪些源码着手&#xff0c;从 简单到深入的方式学习源码&#xff1b; 学习源码也是一个修炼过程&#xff0…

科技改变旅游,道观漫游可视化:智能化管理助力道观游览

道观漫游可视化是一种通过技术手段实现道观游览的可视化展示方式&#xff0c;让游客能够更加直观地了解道观的历史、文化和建筑特色。 随着旅游业的不断发展&#xff0c;道观漫游可视化已经成为了旅游行业中的一个重要方向&#xff0c;吸引了越来越多的游客前来体验。 道观漫游…

Excel 动态拼接表头实现导出

public class Column {//单元格内容private String content;//字段名称&#xff0c;用户导出表格时反射调用private String fieldName;//这个单元格的集合private List<Column> listTpamscolumn new ArrayList<Column>();int totalRow;int totalCol;int row;//exc…

vue使用echarts显示中国地图

项目引入echarts以后&#xff0c;在页面创建canvas标签 引入一个公共js文件&#xff08;下面这段代码就是china.js文件&#xff09; (function (root, factory) {if (typeof define function && define.amd) {// AMD. Register as an anonymous module.define([ex…

孜然地址引导页V9(带后台)

刚刚在浏览之前经常访问的网站的时候我发现他不用那个域名了&#xff0c;然后我见这个页面好看&#xff0c;就把他干下来了&#xff0c;然后把给他写了个后台。另外如果你的子页面收录多的话&#xff0c;人家百度访问你的子页面会显示404的&#xff0c;所以为了流量可观安装这个…

【带头学C++】----- 九、类和对象 ---- 9.8 动态对象创建

目录 9.8 动态对象创建 9.8.1 动态创建对象基础概念 9.8.2 C语言创建动态对象的 9.8.3 new创建动态对象 9.8.4 delete释放动态对象 9.8.5 动态对象数组 9.8 动态对象创建 9.8.1 动态创建对象基础概念 在创建数组时&#xff0c;我们通常需要预先指定数组的长度&#xff0…

三个臭皮匠(ctr,nerdctl,crictl)顶一个诸葛亮(docker)

文章目录 containerd简介 nerdctl简介安装精简 Minimal 安装完整Full 安装启动服务 命令参数容器运行容器列出容器详情容器日志容器进入容器停止容器删除镜像列表镜像拉取镜像标签镜像导出镜像导入镜像删除镜像构建配置tab键配置加速配置仓库http方式https方式 ctr简介命令参数…