数据在内存的存储(2)【浮点数在内存的存储】

一.浮点数以什么形式存储在内存中

根据根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V都可以存储为这样的形式:

V=(-1)^S*M*2^E。

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

(2)M表示有效数字,M是大于等于1,小于2的

(3)2^E表示指数位。

举个例子:比如5.0,写成二进制是101.0,相当于1.01*2^2。则S=0,M=1.01,E=2.

                  比如-5.0,相当于-1.01*2^2。则S=1,M=1.01,E=2.

                  再比如5.5,二进制是101.1,所以为1.011*2^2.则S=0,M=1.011,E=2.

IEEE 754规定:

对于32位的浮点数(float),最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M.

对于64位的浮点数(double),最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M.

这就是关于浮点数在内存中最基础的存储。

二.浮点数存的过程

前面我们说,M我们可以写成1.xxxxx的形式,其中xxxxx是小数部分。当我们保存M的时候,默认这个数的第一位总是1。因此我们可以把这个1舍去,只保存后面的xxxxxx。比如我们存储1.011的时候,只保存011,等到读取的时候,再把第一位的1加上去。这样我们就可以节省出1位有效数字,就像是M本来只能储存23位,但是省去了第一位后,相当于我们最多可以存储24位。

关于E的存储,就有些复杂了,首先它必须是一个无符号的整数。假如E为8位,它的取值范围就是0~255,如果为11,就是0~2047。但是我们知道,这个是指数,科学计数法里是可以出现负数的,所以IEEE 754规定,存入内存的E必须加上一个中间数,对于8位的E,中间数就是127。11位的就是1023.比如,2^10,我们保存成32位时,我们需要保存成137,也就是10001001。

大家注意,float类型是有最大值和最小值的。所以我们的E肯定也是有最大值和最小值的。不过我们不用担心我们加上127或者1023会超出这个范围。

来给大家举个例子

至于为什么是反过来的,可以看我上一篇博客,关于大小端存储的内容。

注意这里我举的例子是5.5在内存中可以精确保存的,但是像是3.14,1.1等等这些数字,是无法再内存中精确保存的。因为我们数据是以二进制存储的,小数点后面是2^-1,2^-2等等,这样的数据对于32位的float是无法精确保存的。

三.浮点数取的过程

1.E不全为1或不全为0

比如0.5的存储

0 01111110 0000000000000000000000

这个最好理解,当我们把存入内存的数据取出来的时候,先把指数E减去127或者1023,得到真实值,再将有效数字M前加上第一位的1(因为我们在存的时候不是把这个省去了吗)。整体的步骤实际上就是把我们存进去的时候完全反了过来。

2.E全为0

0 00000000 00100000000000000000000

这是一种特殊情况,这个时候的E等于1-127或者1-1023这个就是真实值,有效数字M不再加上第一位的1,而是还原成0.xxxxxx的小数。这样做是为了表示±0,以及接近0的很小的数字。

3.E全为1

0 11111111 00100000000000000000000

这个也是一个特殊情况,这里我们有八个1,表示的十进制数是255,大家可以想想,因为我们是加完127之后得到的这个数字,那么真实值就是255-127=128。那么也就是说,这个数字是2^128这是一个天文数字。所以它就表示的是正负无穷大的数字。

四.练习

来看一下这四个输出的是什么结果。

#include<stdio.h>
int main()
{int a = 9;float* pfloat = (float*)&a;printf("a=%d\n", a);printf("*ploat=%f\n", *pfloat);*pfloat = 9.0;printf("a=%d\n", a);printf("*ploat=%f", *pfloat);return 0;
}

这个就要用到我刚才写的那些内容了。

第一个printf就不用多说,输出的肯定是9。

第二个值是几呢?9的二进制是1001,补成32位之后是00000000000000000000000000001001,这里我们把a的地址取出来,因为&a的类型是int*所以这里肯定要强制转换成float*。此时的pfloat指向的就是一个float*类型的a。站在pfloat的角度,它会认为自己指向的是一个float的类型。所以这里的32位就会被理解成是用浮点数存储的方式。也就是

0 00000000 00000000000000000001001

这种情况就是我们上面说的E为全0的特殊情况。E的值就是-126,有效数字M也不再加上第一位的1.所以这里就是(-1)*0.00000000000000000001001*2^-126这个值就直接约等于0了。

第二个打印出来结果:0.000000

第三个的结果我们是把浮点数类型的9.0用%d打印出来,其实只要理解了第二个这一个也不算难了。回想一下浮点数在内存的存储。9.0的二进制是1001.0也就是(-1)^01.001*2^3.S=0,E=3,M=1.001。所以0 10000010 00100000000000000000000这个就是9.0在内存的存储。但是这里打印的是用%d打印,认为内存里的是有符号说,所以这里的最高位0代表的就是正。而正数的原码,反码和补码都是一样的。所以我们就按照这个原码来打印出来。

第三个打印出来的结果:1,091,567,616

这那么最后一个打印出来的这个就是以浮点数的形式打印的,所以就是9.000000

好了,到这里就把数据在内存中的存储就全部讲完了。感谢大家的观看,如有错误,请大家多多指出。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PEReDi 完全隐私的央行数字货币方案

第一个对完全隐私保护建模的方案&#xff0c;基于账户模型&#xff0c;要求交易双方都在线。 角色分类 中央银行 B B B&#xff1a;负责发行数字货币和货币政策&#xff0c;但不控制用户账户的状态&#xff0c;没有能力对交易的发送者或接收者进行去匿名化或披露与特定交易相…

【Nebula笔记】基础操作

目录 一、预备~ 二、基础操作 (一) 图空间 1. 创建图空间 2. 清空图空间 3. 其他 4. FAQ 执行DROP SPACE语句删除图空间后&#xff0c;为什么磁盘的大小没变化&#xff1f; (二) 点类型 1. 创建Tag 2. 删除Tag 3. 更新Tag 4. 其他 (三) 边类型 1. 创建Edge type…

Gin中的gin.Context与Golang原生的context.Context区别与联系

一.gin中的context gin.Context 1.概念 在 Gin 中&#xff0c;Context 是一个非常重要的概念&#xff0c;它是Gin的核心结构体之一,用于处理 HTTP 请求和响应,在 Gin 的处理流程中&#xff0c;Context 贯穿整个处理过程&#xff0c;用于传递请求和响应的信息Gin 的 Context 是…

hadoop安装及基本使用

环境准备 三台centos7虚拟机&#xff0c;设置固定ip&#xff08;自己设置&#xff09;&#xff0c;设置ssh秘密登录&#xff08;自己设置&#xff09;&#xff0c;安装jdk8&#xff08;自己安装&#xff09; 准备安装包hadoop-3.3.6.tar.gz 位置在/home/hadoop 准备服务器之间…

C语言:编译与链接

目录 前言1. 翻译环境与运行环境2.翻译环境&#xff1a;预编译编译汇编链接3. 运行环境 前言 我们写一个程序&#xff0c;例如test.c或是test.h这些源文件&#xff0c;头文件&#xff0c;事实上这些代码都是文本文件&#xff0c;但是计算机能够看得懂&#xff0c;并且直接执行…

从IO操作与多线程的思考到Redis-6.0

IO操作->线程阻塞->释放CPU资源->多线程技术提升CPU利用率 在没有涉及磁盘操作和网络请求的程序中&#xff0c;通常不会出现线程等待状态。线程等待状态通常是由于线程需要等待某些事件的发生&#xff0c;比如I/O操作完成、网络请求返回等。如果程序只是进行计算或者简…

vue前端标准

此文档的目的是让前端和产品、服务端开发&#xff0c;相互之间形成一种默契。 比如一些通用设计&#xff0c;不需要产品去说明&#xff0c;我们默认怎么做。 以及&#xff0c;我们开发之间的默契。 期盼大家的补充 开发原则&#xff1a; 感谢各位开发大佬共建原则&#xf…

项目管理商业文件--商业论证与效益管理计划

本文描述从事项目管理和了解项目管理领域所需的基本知识&#xff0c;词汇定义来自于《项目知识管理体系》(PMBOK指南)第六版&#xff0c;仅作个人学习使用&#xff0c;任何对此文章的引用&#xff0c;应当说明源出处&#xff0c;不得用于商业用途。 如有侵权、联系速删 文章目录…

C# LINQ笔记

C# LINQ笔记 from子句 foreach语句命令式指定了按顺序一个个访问集合中的项。from子句只是声明式地规定集合中的每个项都要访问&#xff0c;并没有指定顺序。foreach在遇到代码时就执行其主体。from子句什么也不执行&#xff0c;只有在遇到访问查询变量的语句时才会执行。 u…

LED和数码管及按键

目录 LED LED灯亮的原理图 LED灯光闪烁 电路设计 keil文件 LED流水灯的实现 keil文件 数码管 显示的基本原理 LED数码管的显示方式 静态显示方式 动态显示方式 具体案例 数码管静态显示 电路图 keil文件 数码管动态显示 电路图 keil文件 74LS138译码器 译…

如何快速进行城市内涝模拟?HTWATER软件

原文链接&#xff1a;如何快速进行城市内涝模拟&#xff1f;HTWATER软件https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247599079&idx2&sndc6f3da8b17c5587cf5b7766e7019729&chksmfa820200cdf58b16658983ecfbf2b369bff39813302942d6f7eb7b71428c68da71…

Vue+OpenLayers7入门到实战:OpenLayers图形绘制功能,OpenLayers实现在地图上绘制线段、圆形和多边形

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上实现图形绘制功能,OpenLayers地图实现在地图上绘制线段、圆形和多边形等基本图形。 注意:本章需要用到Element-UI组件,可能需要额外安装依赖,这里跳过不详述,具体…