C进阶_C语言_浮点数存储规则_浮点型在内存中的存储

news2024/9/22 19:35:13

在开始讲解之前,我们看一下常见浮点数的写法:

3.14159

1E10(它代表1.0乘以10的10次方)

浮点型家族里有float、double、long double类型。

浮点型的表示范围是多少?我们打开float.h就能看到(这里用everything找到了float.h)。

 打开后可以看到关于float、double型的精度、最大值、最小值等信息:

注释已标注。这里了解即可。需要的时候可以来这里查询下。

那么浮点数到底怎么在内存中存储呢?

我们先看下这个例子:

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

可以看到,变量n是int型,但是在定义指针变量pFloat时对n的地址类型进行了强制转换,以float型地址存放在pFloat中。

打印n的值时以int型打印,打印*pFloat时以float型打印。

在给*pFloat赋值9.0后,以int型打印n,以float型打印*pFloat。

那么打印出来的值是多少呢?

经运行,可得到以下结果:

先看第一次打印n时,9是以int型存放在变量n中,打印时以%d也就是int型打印,那么打印的值就是9。

如果以float型指针去存放n的地址,并且以float型打印,那么打印出的结果就不是9了。

这说明int和float两种数据类型的存储方式不一样。

在给*pFloat赋值时,这次是以float型将9.0存放到变量n中,然后以int型打印n。

打印的值并不是9。

而以float型打印*pFloat时得到了9.000000,是预期结果,也就是说这次是以浮点数存进去,再以浮点数拿出来。

这再次印证了int和float两种数据类型的存储方式不一样。

num和*pFloat在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?

要理解这个结果,一定要搞懂浮点数在计算机内部的表示方法。

浮点数存储规则

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

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

也就是说,任何一个二进制浮点数都可以用以下形式表示:

 我们看v=5.5,转化为二进制就是101.1,转化为科学计数法就是1.011*2^2(是二进制,所以底数为2)。

 再规范一下,就是(-1)^0*1.011*2^2。这个数为正数,所以-1的指数就是0。

再举两个例子:

十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。

那么,按照上面V的格式,可以得出S=0,M=1.01,E=2。

十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。

任何一个浮点数,只有S、M、E在发生变化。

IEEE 754规定:

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

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

IEEE 754对有效数字M和指数E,还有一些特别规定:

前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

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

比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。

这样做的目的,是节省1位有效数字。

以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

至于指数E,情况就比较复杂。

首先,E为一个无符号整数(unsigned int)

这意味着,如果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。

然后,指数E从内存中取出还可以再分成三种情况:

E不全为0或不全为1:

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

比如:

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

0 01111110 00000000000000000000000

E全为0:

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

举个例子,一个单精度浮点数为(-1)^0*1.xxxx……*2^(-127),它的E为-127,那么在存储时加上127,值为0。如果有比-127更小的E,那加上127也是0。

它是一个很小的数,非常接近于0的数字,所以要还原为0.xxxxxx的小数。

E全为1:

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

比如看这个数,1.xxxxxx*2^128,它是一个非常大的数。128加上127就是255,用二进制表示就全是1。如果有比128更大的数,加上127后二进制形式还全是1。这时不论原数字的真实值是多少,都表示一个±无穷大的数。

再看两个例子:

为什么0x00000009还原成浮点数,就成了0.000000?

首先,将0x00000009拆分,得到第一位符号位s=0,后面8位的指数 E=00000000

最后23位的有效数字M=000 0000 0000 0000 0000 1001。

9 -> 0000 0000 0000 0000 0000 0000 0000 1001

由于指数E全为0,所以符合上一节的第二种情况。因此,浮点数V就写成:

V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000。

请问浮点数9.0,如何用二进制表示?还原成十进制又是多少?

首先,浮点数9.0等于二进制的1001.0,即1.001×2^3。

9.0 -> 1001.0 ->(-1)^01.0012^3 -> s=0, M=1.001,E=3+127=130

那么,第一位的符号位s=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130,即10000010。

所以,写成二进制形式,应该是S+E+M,即

0 10000010 001 0000 0000 0000 0000 0000

这个32位的二进制数,还原成十进制,正是 1091567616 。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么牌子的蓝牙耳机好?好用的蓝牙耳机排行

现如今&#xff0c;蓝牙耳机的用途越来越广泛&#xff0c;无论是追剧、游戏、通话、运动等&#xff0c;都能看到使用蓝牙耳机的人。在日常的使用中蓝牙耳机也逐渐取代有线耳机成为受人们欢迎的存在&#xff0c;那么&#xff0c;什么牌子的蓝牙耳机好&#xff1f;接下来&#xf…

功能强大的python包sklearn

1. sklearn简介sklearn是基于python语言的机器学习工具包&#xff0c;是目前做机器学习项目当之无愧的第一工具。 sklearn自带了大量的数据集&#xff0c;可供我们练习各种机器学习算法。 sklearn集成了数据预处理、数据特征选择、数据特征降维、分类\回归\聚类模型、模型评估等…

基于YOLO实践布匹缺陷检测

在缺陷检测领域中&#xff0c;越来越多看到AI的身影&#xff0c;路面缺陷、生产缺陷、PCB缺陷、瓶装酒缺陷检测等等&#xff0c;目标检测等模型发挥着越来越多的作用&#xff0c;像瓷砖缺陷和布匹缺陷这类平面类型的缺陷也不例外&#xff0c;最近做的项目中大多和这类型的数据有…

回顾2022,那些令人印象深刻的AI突破

文 | 付奶茶2022年是令人印象深刻的一年。在这一年中&#xff0c;我们目睹了许多前所未有的AI模型的出现&#xff0c;这些模型不断刷新着人类对AI力量的认知。关于这一年中最好的工作&#xff0c;每个人都有自己不同的看法。在这篇文章中&#xff0c;我们跟随Alan D. Thompson在…

对Mysql 超时配置项进行深入理解!

1 JDDB超时JDBC 是 Java 应用程序中用于访问数据库的一套标准 API类型4驱动是通过socket来处理字节流的。如果socket超时设置不合适&#xff0c;类型4驱动也可能有同样的错误&#xff08;连接被阻塞&#xff09;。1.2 JDBC超时层次应用程序WAS与数据库间的超时的层次更上层的超…

STL模拟实现——string

前言 STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且 是一个包罗数据结构与算法的软件框架。 STL有六大组件&#xff1a;算法&#xff0c;容器&#xff0c;迭代器&#xff0c;仿函数&am…

从0搭建一个WebRTC,实现多房间多对多通话,并实现屏幕录制

这篇文章开始会实现一个一对一WebRTC和多对多的WebRTC&#xff0c;以及基于屏幕共享的录制。本篇会实现信令和前端部分&#xff0c;信令使用fastity来搭建&#xff0c;前端部分使用Vue3来实现。 为什么要使用WebRTC WebRTC全称Web Real-Time Communication&#xff0c;是一种实…

安全狗重磅发布数据安全解决方案·数垒

一、 势在必行的数据安全 近年来&#xff0c;随着《网络安全法》、《数据安全法》、“数据二十条”等多部法律、意见法规等的相继颁布&#xff0c;数据安全管理与防护在国家政策上成为势在必行的行动之一。与此同时&#xff0c;伴随着数字经济时代的到来&#xff0c;数以万计…

Java基础语法-学习笔记

目录 01Java语言的发展 02Java的三大平台 03Java的主要特性 04JRE和JDK 1. 注释 使用的技巧 注意点 2. 关键字 2.1 概念 2.2 第一个关键字class 3. 字面量 区分技巧 4. 变量 4.1 什么是变量&#xff1f; 4.2 变量的定义格式 5. 数据类型 5.1 Java语言数据类型的…

STM32——TIM输出比较

文章目录一、TIM输出比较输出比较简介PWM简介输出比较通道(高级)输出比较通道(通用)输出比较模式控制器工作原理PWM基本结构参数计算三、PWM驱动LED呼吸灯电路设计关键代码关键函数与参数引脚重映射取消默认调试功能函数极性选择决定占空比&#xff0c;周期的三个函数四、PWM驱…

Design pattern-js的设计模式(一)

前言 什么是设计模式&#xff1f;&#xff08;Design pattern&#xff09;代表了最佳的实践&#xff0c;通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间…

【youcans 的 OpenCV 例程 300篇】254.OpenCV 绘制图像标记

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程 300篇】254. OpenCV 绘制标记 7.1 绘图函数基本参数 OpenCV提供了绘图功能&#xff0c;可以在图像上绘制直线、矩形、圆、椭圆等各种几何图形。 函数 cv.line()、cv.rectangle()、cv.circle()、cv.polyli…

深度学习:08 训练、测试和验证集的说明

目录 用于深度学习的数据集 训练集 验证集 测试集 总结 用于深度学习的数据集 接下来&#xff0c;我将在这篇里面讨论在训练和测试神经网络期间使用的不同数据集。 出于模型的训练和测试目的&#xff0c;我们应该将数据分解为三个不同的数据集。这些数据集将包含以下内容…

【小f的刷题笔记】(JS)阶乘 - 阶乘后的零 LeetCode172 阶乘函数后K个零 LeetCode793

【阶乘】 一、阶乘后的零&#xff1a; LeetCode172 链接&#xff1a; 172.阶乘后的零 题目&#xff1a; 思路&#xff1a; 0的产生是一定是因为2*5产生的&#xff0c;所以就是找因数 并且&#xff0c;可想而知&#xff0c;找的到因数5&#xff0c;必然找的到因数2与之搭配…

【MySQL】深入理解B+树索引

文章目录1. 前言2. 索引方案3. InnoDB的索引方案4. 索引的分类4.1 聚簇索引4.2 二级索引4.3 联合索引5. InnoDB中的B树索引的注意事项5.1 内节点中目录项记录的唯一主5.2 一个页至少容纳2条记录6. MyISAM中的索引⽅案简单介绍1. 前言 索引&#xff0c;是MySQL快速查询的秘籍。…

ARMv8/ARMv9:深入理解MPIDR_EL1寄存器中的affinity

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈官方文档(ARM ARM文档)的介绍如下所示 翻译一下MPIDR_EL1相关的英文,如下所示: 作用: 在多处理器系统中,为调…

Xshell 连接虚拟机(Ubuntu、CentOS)

对于一些linux的初学者来说&#xff0c;在没有自己的服务器时可以选择使用虚拟机来代替&#xff08;如ubuntu、centos等&#xff09;进行相关的学习。下面介绍下如何使用xshell来远程连接虚拟机。 注意&#xff1a;下面我以Ubuntu来举例说明。 1、创建虚拟机 虚拟机的创建网络…

1、数据库安装修改root密码管理自启服务

MySQL的下载和安装 登录MySQL官网下载MySQL.zip包 MySQL :: Download MySQL Community Server 下载完毕可自行选择存储位置&#xff0c;进行解压 解压后配置环境变量 完成配置后在MySQL目录下新建一个my.ini配置文件 文件写入以下内容 [client] # 设置mysql客户端默认字符集…

面向对象2(static修饰变量和方法、Javabean类、测试类和工具类、对main方法的理解、继承、子类继承父类构造方法变量和方法)

1、static修饰变量和方法 JDK8以前&#xff0c;静态区在方法区里面&#xff0c;JDK8开始&#xff0c;静态区挪到了堆内存当中 理解&#xff1a; 因为静态方法没有this&#xff0c;而非静态方法是有一个隐含的参数this的&#xff0c;所以想在静态方法里面调用非静态变量或方法就…

电子招标采购系统源码之传统采购模式面临的挑战

采购类型多 采购制度&#xff1a;采购金额、部门、品类的差异导致管理标准不同。 采购流程&#xff1a;从供应商管理、寻源操作到合同签订、订单执行&#xff0c;业务流程长&#xff0c;审批节点多&#xff0c;传统管理透明度低&#xff0c;联动性差。 供应商管理难 寻源&#…