浮点数详解

news2024/11/15 20:09:20

目录

1.概述

2.浮点数的编码方式

2.1.float类型的IEEE编码

2.2.double类型的IEEE编码

2.3.现场问题

2.4.总结


1.概述

        计算机也需要运算和存储数学中的实数。在计算机的发展过程中,曾产生过多种存储实数的方式,有的现在已经很少使用了。不管如何存储,都可以将其划分为定点实数存储方式和浮点实数存储方式两种。所谓定点实数,就是约定整数位和小数位的长度,比如用4字节存储实数,我们可以约定两个高字节存放整数部分,两个低字节存储小数部分。这样做的好处是计算效率高,缺点也显而易见:存储不灵活,比如我们想存储65536.5,由于整数的表达范围超过了2字节,就无法用定点实数存储方式了。对应地,也有浮点实数存储方式,道理很简单,就是用一部分二进制位存放小数点的位置信息,我们可以称之为“指数域”,其他的数据位用来存储没有小数点时的数据和符号,我们可以称之为"数据域" "符号域"。在访问时取得指数域,与数据域运算后得到真值,如67.625,利用浮点实数存储方式,数据域可以记录为67625,小数点的位置可以记为10的-3次方,对该数进行访问时计算一下即可。浮点实数存储方式的优缺点和定点实数存储方式的正好相反。在80286之前,程序员常常为实数的计算伤脑筋,而后来出现的浮点协处理器,可以协助主处理器分担浮点运算程序员计算实数的效率因此得到提升,于是浮点实数存储方式也就普及开来,成为现在主流的实数存储方式。但是,在一些条件恶劣的嵌入式开发场合,仍可看到定点实数的存储和使用。
        在 C/C++中,使用浮点方式存储实数,用两种数据类型来保存浮点数: foat(单精度)和double(双精度)。float在内存中占4字节,double在内存中占8字节。由于占用空间大,double可描述的精度更高。这两种数据类型在内存中同样以十六进制方式存铺,但写大类型有所不同。
        整型类型是将十进制转换成二进制保存在内存中,以十六进制方式显示。浮点类型并不是将一个浮点小数直接转换成二进制数保存,而是将浮点小数转换成的二进制码重新编码,再进行存储。C/C++的浮点数是有符号的。
        在C/C++中,将浮点数强制转换为整数时,不会采用数学上四舍五人的方式,而是食弃掉小数部分,不会进位。
        浮点数的操作不会用到通用寄存器,而是会使用浮点协处理器的浮点寄存器,专门对浮点数进行运算处理。

2.浮点数的编码方式

        浮点数编码转换采用的是IEEE 规定的编码标准,float 和 double 这两种类型数据的转换原理相同,但由于表示的范围不一样,编码方式有些许区别。IEEE规定的浮点数编码会将一个浮点数转换为二进制数。以科学记数法划分,将浮点数拆分为3部分:符号、指数、尾数。

2.1.float类型的IEEE编码

        foat类型在内存中占4字节(32位)。最高位用于表示符号,在剩余的31位中,从左向右取8位表示指数,其余表示尾数,如下图所示。

76789abd6c2a47ad93b749a2f3bcc3f6.png
        在进行二进制转换前,需要对单精度浮点数进行科学记数法转换。例如,将foat类型的12.25f转换为IEEE编码,须将12.25f转换成对应的二进制数1100.01,浮点数转二进制的方法为:二进制表示整数时,最低位代表2的0次方,往高位依次是2的1次方,2次方,3次方……那么对应的,二进制数小数点后面,最高位则是2的-1次方,-2次方,-3次方……如下图所示:

        举几个例子:

        那么12.25f转换成对应的二进制数的整数部分为1100,小数部分为01;小数点向左移动,每移动1次,指数加1,移动到除符号位的最高位为1处,停止移动,这里移动3次。对12.25f进行科学记数法转换后二进制部分为1.10001,指数部分为 3。在IEEE 编码中,由于在二进制情况下,最高位始终为1,为一个恒定值,故将其忽略不计。这里是一个正数,所以符号位添加0。
        12.25f经 IEEE 转换后各位如下。
        1)符号位:0
        2)指数位:十进制 3+127=130,转换为二进制为10000010。
        3)尾数位:10001000000000000000000(当不足23位时,低位补0填)。

        由于尾数位中最高位1是固定值,故忽略不计,只要在转换回十进制数时加1即可。为什么指数位要加 127呢?这是因为指数可能出现负数,十进制数 127 可表示为二进制数01111111,IEEE编码方式规定,当指数小于0111111时为一个负数,反之为正数,因01111111为0
        将示例中转换后的符号位、指数位和尾数位按二进制拼接在一起,就成为一个完整的IEEE 浮点编码:01000001010001000000000000000000。转换成十六进制数为0x41440000内存中以小端方式进行排列,故为 00004441,分析结果如下图所示。 2ec9d132f26b4dbe9af83f805987bce4.png

        使用第三方工具软件计算更清楚更简便,如下图所示:

aa6690950d3b4ff1b8b9396a73bb5299.png

        上面演示了符号位为正、指数位也为正的情况。那么什么情况下指数位可以为负呢?根据科学记数法,小数点向整数部分移动时,指数做加法。相反,小数点向小数部分移动时,指数需要以0起始做减法。浮点数-0.125f转换EEE编码后,将会是一个符号位为1、指数部分为负的数。-0.125f经转换后二进制部分为0.001,用科学记数法表示为1.0,指数为 -3。
        -0.125fIEEE 转换后各位的情况如下。
        1)符号位:1。
        2)指数位:十进制 127+(-3 ),转换为二进制是 01111100,如果不足8位,则高位补 0。
        3)尾数位:00000000000000000000000。

        -0.125f转换后的 IEEE 编码二进制拼接为 10111110000000000000000000000000。转换成十六进制数为 0xBE000000,内存中显示为00 00 00 BE,分析结果如下图所示。

006985ecf4b94acfa729146129c5608c.png

        使用第三方工具软件计算更清楚,如下图所示: 

b0b093a22ca347c699bd58a4cc0af742.png

        上面的两个浮点数小数部分转换为二进制时都是有穷的,如果小数部分转换为二进时得到一个无穷值,则会根据尾数部分的长度舍弃多余的部分。如单精度浮点数1.3f,数部分转换为二进制就会产生无穷值,依次转换为0.3、0.6、1.2、0.4、0.8、1.6、1.2、00.8……转换后得到的二进制数为 1.01001100110011001100110,到第23 位终止,尾数部分无法保存更大的值。

        1.3f经 EEE 转换后各位的情况如下:
        1)符号位:0。
        2)指数位:十进制 0+127,转换二进制01111111。
        3)尾数位:01001100110011001100110。

        1.3f转换后的IEEE编码二进制拼接为00111111101001100110011001100110。转换十六进制数为0x3FA66666,在内存中显示为66 66 A6 3F。由于在转换二进制过程中产些了无穷值,舍弃了部分位数,所以进行IEEE编码转换后得到的是一个近似值,存在一定的误差。再次将这个IEEE编码值转换成十进制小数,得到的值为12516582,四合五人保留位小数之后为1.3。这就解释了为什么C++在比较浮点数值是否为0时,要做一个区同中较而不是直接进行等值比较。正确浮点数比较如下代码:

float f1=0.0001f;
if(f2 >=-f1 6& f2 <= f1)
{
    // f1等于0
}

2.2.double类型的IEEE编码

        前文讲解了单精度浮点类型的IEEE编码。double类型和 foat类型大同小异,只是double类型表示的范围更大,占用空间更多,是 foat类型所占空间的两倍。当然,精准度double 类型占8字节的内存空间,同样,最高位也用于表示符号,指数位占11位,剩也会更高。
        在 float类型中,指数位范围用8位表示,加127后用于判断指数符号。在double类型余 52 位表示位数。中,由于扩大了精度,因此指数范围使用11位正数表示,加1023 后可用于指数符号判断。double 类型的 IEEE 编码转换过程与 foat 类型一样,读者可根据 foat类型的转换流程来转换 double类型,此处不再赘述。

2.3.现场问题

        通过上面的讲解,我们知道浮点数是有可能出现经过IEEE编码转换后得到的是一个近似值,跟实际值存在一定的偏差。项目前期制定的设备两端通信协议设计某些字段为double类型,导致采集数据设备采集到的两端的二进制数据不一致的问题。后期调整,全部把double类型的数据转换为整数进行传输,才保证了两端二进制数据的一致性。

2.4.总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注本博客的其它内容。

参考:

浮点数与十六进制转换工具下载地址:https://download.csdn.net/download/haokan123456789/88771127?spm=1001.2014.3001.5501   浮点类型(float、double)在内存中如何存储?-腾讯云开发者社区-腾讯云
C++:float型数据存储原理及精度丢失溢出深入解析 - 知乎

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

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

相关文章

OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

1. 介绍 差值哈希算法&#xff08;Difference Hash Algorithm&#xff0c;简称dHash&#xff09; 是哈希算法的一种&#xff0c;主要可以用来做以图搜索/相似图片的搜索工作。 2. 原理 差值哈希算法通过计算相邻像素的差异来生成哈希&#xff0c;即通过缩小图像的每个像素与平…

macbookpro怎么恢复出厂设置2024最新恢复方法汇总

可能你的MacBook曾经是高性能的代表&#xff0c;但是现在它正慢慢地逝去了自己的光芒&#xff1f;随着逐年的使用以及文件的添加和程序的安装&#xff0c;你的MacBook可能会开始变得迟缓卡顿&#xff0c;或者失却了以往的光彩。如果你发现你的Mac开始出现这些严重问题&#xff…

c#中使用UTF-8编码处理多语言文本的有效策略

使用UTF-8编码处理多语言文本的有效策略 在当今的全球化时代&#xff0c;软件开发者常常需要处理包含多种语言的文本。这不仅涉及英文和其他西方语言&#xff0c;还包括中文、日文、韩文等多字节字符系统。在这篇博客中&#xff0c;我将探讨如何有效地使用UTF-8编码来处理混合语…

基于SpringBoot Vue二手闲置物品交易系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

unity shaderGraph实例-武器特效(纹理遮罩,纹理动画,纹理变形)

文章目录 效果展示所需素材整体结构各区域内容区域1区域2区域3区域4区域4-1区域4-2区域4-3区域4-4 区域5区域6 后处理工程下载 效果展示 所需素材 除了剑的模型外&#xff0c;主要是这五张贴图&#xff0c;其中swordmask和swordmask1中白色的区域是剑身的位置&#xff0c;sword…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具&#xff0c;掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…

上门回收小程序,打造回收新模式

近年来&#xff0c;我国一直秉持着环保绿色的发展理念&#xff0c;为了减少资源浪费&#xff0c;旧物回收成为了人们处理废弃物品的方式。目前&#xff0c;我国回收市场规模大约能达到3.58亿元&#xff0c;在我国经济的稳定增长和环保意识的提高下&#xff0c;回收市场规模还将…

【Java】--网络编程:基于TCP协议的网络通信

【Java】–网络编程&#xff1a;基于TCP协议的网络通信 文章目录 【Java】--网络编程&#xff1a;基于TCP协议的网络通信一、TCP协议1.1 概念1.2 三次握手1.2.1 文字描述1.2.2 画图演示 1.3 四次挥手1.3.1 文字描述1.3.2 画图演示 二、基于TCP的Socket网络编程2.1 概念2.2 服务…

Android 通过adb命令查看应用流量

一. 获取应用pid号 通过adb shell ps -A | grep 包名 来获取app的 pid号 二. 查看应用流量情况 使用adb shell cat /proc/#pid#/net/dev 命令 来获取流量数据 备注&#xff1a; Recevice: 表示收包 Transmit: 表示发包 bytes: 表示收发的字节数 packets: 表示收发正确的…

thinkphp+vue+mysql旅游推荐攻略分享网站p0667

基于php语言设计并实现了旅游分享网站。该系统基于B/S即所谓浏览器/服务器模式&#xff0c;应用thinkphp框架&#xff0c;选择MySQL作为后台数据库。系统主要包括用户、景点信息、攻略分类、旅游攻略、门票购买、留言反馈、论坛管理、系统管理等功能模块。运行环境:phpstudy/wa…

实现纯Web语音视频聊天和桌面分享(附源码,PC端+移动端)

在网页里实现文字聊天是比较容易的&#xff0c;但若要实现视频聊天&#xff0c;就比较麻烦了。本文将实现一个纯Web版的视频聊天和桌面分享的Demo&#xff0c;可直接在浏览器中运行&#xff0c;不需要安装任何插件。 一. 主要功能及支持平台 1.本Demo的主要功能有 &#xff…

第10次修改了可删除可持久保存的前端html备忘录

第10次修改了可删除可持久保存的前端html备忘录 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>…

03_list

文章目录 list接口list的APIlistIterator方法subList方法 ArrayListArrayList的源码阅读 LinkedListVectorStack list接口 特点&#xff1a; List是Collection的子接口&#xff0c;是描述数据存储的接口数据结构表现为线性表&#xff0c;可以通过下标来操作存储数据有序可以存…

x-cmd pkg | frp - 内网穿透工具

简介 frp&#xff08;Fast Reverse Proxy&#xff09;是一个专注于内网穿透的高性能反向代理应用&#xff0c;可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 它采用 C/S 模式&#xff0c;将服务端部署在具有公网 IP 的机器上&#xff0c;客户端部…

身份验证遇到问题,登陆ChatGPT时提示:“we ran into an issue while authenticating you…”

oops&#xff01; we ran into an issue while authenticating you, if this issue persists, please contact us through our help center at help.openai.com 说明&#xff1a;哎呀&#xff01;我们在验证您的身份时遇到了一个问题&#xff0c;如果这个问题仍然存在&#xff…

【Linux】【实战系列】10 分钟掌握日常开发中 Linux 网络处理相关命令

文章目录 lsofnetstatpingnslookupsshssh-keygenscpsftp 网络工具 curl网络工具 wget最后个人简介 hello&#xff0c;大家好&#xff0c;我是 Lorin&#xff0c;上一期和大家分享一期日常开发中常用的 Linux 文件和文本命令实战教学&#xff0c;这一期给大家带来常用的网络处理…

五、垃圾回收

1. 垃圾回收基础 1.1 什么是垃圾 简单说就是&#xff1a;内存中已经不再被使用到的内存空间就是垃圾。 1.2 如何判定是垃圾 1.2.1 引用计数法 引用计数法&#xff1a;给对象添加一个引用计数器&#xff0c;有访问就 1&#xff0c;引用失效就 -1 引用计数法的优缺点&#…

docker容器下php框架laravel的使用问题与解决方案

DB_CONNECTIONmysqlDB_HOSTlocalhost DB_CONNECTIONmysqlDB_HOSTdocker33-mysql-1 容器中只有数据库结构 进入MySQL容器内&#xff0c;创建表结构&#xff0c;添加数据 代码层面需要转换成数组 $query->get([*])->toArray(); 分页数据框架会返回带有data的数据&#xf…

【QT+QGIS跨平台编译】之六:【LZMA+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、lzma介绍二、文件下载三、文件分析四、pro文件五、编译实践一、lzma介绍 LZMA(Lempel-Ziv-Markov chain-Algorithm的缩写),是一个Deflate和LZ77算法改良和优化后的压缩算法。 libLzma是基于LZMA压缩算法封装的开源库。2001年被首次应用于7-Zip压缩工具中,是 …

vscode设置terminal的最大行数

今天跑代码出现一个问题&#xff0c;就是整个程序跑完&#xff0c;整个程序的输出信息过多&#xff0c;最开始输出的信息已经被vscode的缓存冲掉了&#xff0c;只能看到最后的一部分&#xff0c;具体的原因是vscode的terminal默认只能保存1000行的信息&#xff0c;所以如果想保…