IEEE754浮点格式与解析

news/2025/10/8 0:22:43/文章来源:https://www.cnblogs.com/misaka114514/p/19126087

0 前言

在完成学校RM嵌入式软件组的作业时遇到了一个问题:将0x00,0x00,0x20,0x40这四个十六进制数据根据一定规则变为浮点数2.5f,我询问AI得知这与IEEE754的浮点数存储规则有关,这篇随笔就来记录一下。

1.IEEE 754简介

IEEE 754为二进制浮点数的表示制定了一个标准,任何一个二进制浮点数 \(x\) 都可以由符号位 \(S\)、尾数 \(M\) 和指数(也叫阶码) \(E\) 表示,即 \(x=(-1)^S\times M \times 2^E\)
其中,符号位 \(S\)\(0\) 表示正数,为 \(1\) 表示负数。
尾数 \(M\) 表示一个形如 \(1.0100111\) 的二进制数,IEEE 754标准下所有的尾数都以1开头,所以通常尾数 \(M\) 不存储小数点前的1,这可以多存一位数据,提高精度。
阶码 \(E\) 实际存储了实际指数+偏置值,偏置值在单精度浮点数(float)下表示为127,而在双精度(double)下表示为1023.这样做的目的是方便比较,使得指数大的浮点数,其二进制表示也更大。

类型 符号位 阶码 尾数 总位数
float 1 8 23 32
double 1 11 52 64

上述规则是针对规格值表示的,还有非规格值和非数字两种类型,他们使用不同的规则,此处按下不表。
我们来举个例子:将-12.375转换为IEEE 754单精度格式。
首先确定符号位为1.
然后我们将12.375转换为二进制小数:\((12.375)_{10}=(1100.011)_2\)
将小数部分表示为二进制下的“科学计数法”的形式:\((1100.011)_2=(1.100011\times 2^3)_2\)
这样,我们确定了尾数 \(M=(10001100000000000000000)_2\) ,(根据规则,已经舍去小数点前的1,并补零至32位),而实际的指数为3,即阶码 $E=3+127=(130)_{10}=(10000010)_2}。
最后,我们把这三部分缝合起来,就得到了-12.375在IEEE 754下的表示:

点击查看代码
1 10000000 10000000000000000000000
↑ ↑        ↑
| |        |
| |        +-- 尾数位 (23位): 10001100000000000000000
| +--------- 指数位 (8位): 10000010 = 130
+---------- 符号位 (1位): 1

2.巧用memcpy函数进行IEEE 754浮点数与十六进制数据的转换

根据上述规则可以发现,将一个浮点数转化为IEEE 754形式的一组二进制数或者十六进制数非常麻烦。但是,由于绝大多数计算机都采用了这个规范,所以一个浮点数在内存中的样子就是满足规范的一组二进制数!如果我们把这个二进制数提取出来,我们就自动完成了转换!
以下是我用deepseek写的转换代码。

点击查看代码
#include <iostream>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <vector>/*** @brief 将4字节十六进制数据转换为浮点数* @param hexData 4字节的十六进制数据数组(小端序)* @return 对应的浮点数*/
float hexToFloat(const uint8_t hexData[4]) {uint32_t intValue;// 方法1:使用memcpy(推荐,避免严格别名问题)std::memcpy(&intValue, hexData, 4);// 方法2:手动字节组装(小端序)// intValue = (hexData[3] << 24) | (hexData[2] << 16) | (hexData[1] << 8) | hexData[0];// 将整数表示重新解释为浮点数float result;std::memcpy(&result, &intValue, 4);return result;
}/*** @brief 将浮点数转换为4字节十六进制数据(小端序)* @param value 要转换的浮点数* @param hexData 输出参数,存储4字节十六进制数据*/
void floatToHex(float value, uint8_t hexData[4]) {uint32_t intValue;// 将浮点数的位模式复制到整数中std::memcpy(&intValue, &value, 4);// 按小端序提取字节(最低有效字节在前)hexData[0] = (intValue >> 0) & 0xFF;   // 最低有效字节hexData[1] = (intValue >> 8) & 0xFF;hexData[2] = (intValue >> 16) & 0xFF;hexData[3] = (intValue >> 24) & 0xFF;  // 最高有效字节
}/*** @brief 重载版本:返回十六进制数据向量* @param value 要转换的浮点数* @return 包含4字节十六进制数据的vector*/
std::vector<uint8_t> floatToHex(float value) {std::vector<uint8_t> hexData(4);floatToHex(value, hexData.data());return hexData;
}/*** @brief 打印十六进制数据的详细信息* @param hexData 4字节十六进制数据* @param description 描述信息*/
void printHexData(const uint8_t hexData[4], const std::string& description = "") {if (!description.empty()) {std::cout << description << std::endl;}std::cout << "十六进制: ";for (int i = 0; i < 4; i++) {std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hexData[i]) << " ";}std::cout << std::dec << std::endl;std::cout << "十进制: ";for (int i = 0; i < 4; i++) {std::cout << static_cast<int>(hexData[i]) << " ";}std::cout << std::endl;
}/*** @brief 详细分析浮点数的IEEE 754表示* @param value 要分析的浮点数*/
void analyzeFloat(float value) {uint32_t intValue;std::memcpy(&intValue, &value, 4);uint32_t sign = (intValue >> 31) & 1;uint32_t exponent = (intValue >> 23) & 0xFF;uint32_t mantissa = intValue & 0x7FFFFF;std::cout << "=== IEEE 754 分析 ===" << std::endl;std::cout << "浮点数: " << value << "f" << std::endl;std::cout << "32位表示: 0x" << std::hex << std::setw(8) << std::setfill('0') << intValue << std::dec << std::endl;std::cout << "二进制: ";for (int i = 31; i >= 0; i--) {std::cout << ((intValue >> i) & 1);if (i == 31) std::cout << " ";if (i == 23) std::cout << " ";}std::cout << std::endl;std::cout << "符号位: " << sign << " (" << (sign ? "负数" : "正数") << ")" << std::endl;std::cout << "指数位: " << exponent << " (偏置后: " << (exponent - 127) << ")" << std::endl;std::cout << "尾数位: 0x" << std::hex << mantissa << std::dec << std::endl << std::endl;
}// 测试函数
void testConversions() {std::cout << "========== 浮点数转十六进制测试 ==========" << std::endl;// 测试用例std::vector<float> testFloats = {3.0f, 2.5f, 1.0f, 0.0f, -1.0f, 3.14159f, -123.456f};for (float value : testFloats) {analyzeFloat(value);// 浮点数转十六进制uint8_t hexData[4];floatToHex(value, hexData);printHexData(hexData, "转换后的十六进制数据:");// 十六进制转回浮点数float converted = hexToFloat(hexData);std::cout << "转换回浮点数: " << converted << "f" << std::endl;// 验证精度std::cout << "精度验证: " << (value == converted ? "✓ 完全匹配" : "✗ 存在误差") << std::endl;std::cout << "----------------------------------------" << std::endl;}
}void testSpecificCases() {std::cout << "\n========== 特定用例测试 ==========" << std::endl;// 测试已知的转换对struct TestCase {float value;uint8_t expectedHex[4];const char* description;};TestCase testCases[] = {{3.0f,   {0x00, 0x00, 0x40, 0x40}, "3.0f"},{2.5f,   {0x00, 0x00, 0x20, 0x40}, "2.5f"},{1.0f,   {0x00, 0x00, 0x80, 0x3F}, "1.0f"},{0.0f,   {0x00, 0x00, 0x00, 0x00}, "0.0f"},{-1.0f,  {0x00, 0x00, 0x80, 0xBF}, "-1.0f"}};for (const auto& testCase : testCases) {std::cout << "测试: " << testCase.description << std::endl;// 十六进制转浮点数float result = hexToFloat(testCase.expectedHex);std::cout << "十六进制 → 浮点数: " << result << "f" << std::endl;// 浮点数转十六进制uint8_t hexData[4];floatToHex(testCase.value, hexData);bool hexMatch = true;for (int i = 0; i < 4; i++) {if (hexData[i] != testCase.expectedHex[i]) {hexMatch = false;break;}}std::cout << "十六进制匹配: " << (hexMatch ? "✓ 成功" : "✗ 失败") << std::endl;std::cout << "----------------------------------------" << std::endl;}
}int main() {// 基本功能演示std::cout << "========== 基本功能演示 ==========" << std::endl;float original = 3.0f;std::cout << "原始浮点数: " << original << "f" << std::endl;// 浮点数转十六进制uint8_t hexData[4];floatToHex(original, hexData);printHexData(hexData, "转换后的十六进制:");// 十六进制转回浮点数float converted = hexToFloat(hexData);std::cout << "转换回浮点数: " << converted << "f" << std::endl;// 使用vector版本的函数auto hexVector = floatToHex(original);std::cout << "Vector版本结果: ";for (uint8_t byte : hexVector) {std::cout << "0x" << std::hex << static_cast<int>(byte) << " ";}std::cout << std::dec << std::endl;// 运行完整测试testConversions();testSpecificCases();return 0;
}

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

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

相关文章

国庆 Day3 强基数学

复数、不等式、方程、代数恒等变形……复数 四种基本表示形式:代数、三角、向量(几何法)、指数(基本同三角)。 一个重要公式:\(|z|^2=z\cdot z(共轭)\)。Trick 1:利用 \(-1=i^2\) 进行代数变形。Eg:\(z^2-2z+2…

制作网站公司 英语网站首页目前主要的网络营销方式

文章目录 前言一、设计框图二、GT_module三、PHY_module3.1、PHY_tx模块3.2、PHY_rx_bitsync模块3.3、PHY_rx模块 四、上板测试 前言 有了对64B66B协议的认识以及我们之前设计8B10B自定义PHY的经验&#xff0c;本文开始对64B66B自定义PHY的设计 一、设计框图 二、GT_module …

网站页面布局模板工业互联网平台首先要提高数据的挖掘能力

[vue] 你知道vue的模板语法用的是哪个web模板引擎的吗&#xff1f;说说你对这模板引擎的理解 模板引擎&#xff1a; 负责组装数据&#xff0c;以另外一种形式或外观展现数据。 优点&#xff1a; 可维护性&#xff08;后期改起来方便&#xff09;&#xff1b; 可扩展性&#…

学校建设门户网站的好处营销型网站建设一般要多少钱

常用音频接口&#xff1a;TDM&#xff0c;PDM&#xff0c;I2S&#xff0c;PCM_tdm音频_沙漠的甲壳虫的博客-CSDN博客 I2S/PCM接口及音频codec_音频pcm接口模块设计-CSDN博客 2个TDM8功放调试ing_周龙(AI湖湘学派)的博客-CSDN博客 数字音频接口时序----IIS、TDM、PCM、PDM_td…

wordpress点赞排行榜宁波seo智能优化

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

py网站开发视频教程网站开发文献资料

字典的每个键值对用冒号分割&#xff0c;键值对之间用逗号分隔&#xff0c;所有键值对包括在{}中。d {key1 : value1, key2 : value2 }键必须是唯一的&#xff0c;值可以不唯一。值可以取任何数据类型&#xff0c;但键必须是不可变对象&#xff0c;如字符串&#xff0c;数字或…

公司网站制作机构邢台做网站的

阅读目录一 数学定义的函数与python中的函数初中数学函数定义&#xff1a;一般的&#xff0c;在一个变化过程中&#xff0c;如果有两个变量x和y&#xff0c;并且对于x的每一个确定的值&#xff0c;y都有唯一确定的值与其对应&#xff0c;那么我们就把x称为自变量&#xff0c;把…

网站建设代码排版出错app订制

python操作文件 open的常用参数&#xff1a; 1.要读取的文件名字或者文件路径 2.文件打开的模式 r:只读模式 rb&#xff1a;以二进制的格式去打开文件 3.encoding&#xff1a;用来指定文件的编码格式&#xff08;使用rb的时候&#xff0c;不需要加该参数&#xff09; #打…

山东省建设工程注册中心网站英文网站建设哪家好

electron 静默下载文件 cooljser 2020-12-24 electron 上传、下载文件是一个很常用的功能&#xff0c;在 electron 中我们不但可以实现和 h5 一样的下载&#xff0c;也可以实现静默下载&#xff0c;让用户无感知。官方的做法是通过mainWindow.webContents.downloadURL(url)来…

宁波建设工程检测行业协会网站汽车企业管理系统

由于原本的数据库命名不规范&#xff0c;需要进行重新命名&#xff0c;最终确定方案为新建数据库后迁移表&#xff0c;以下为脚本。 #!/bin/bashecho -e "\033[34m 此脚本功能为修改数据库名称&#xff08;需要新建数据库后将数据迁移到新数据库&#xff09;&#xff0c;…

默认实现,子类(如 CRenderDevice_Renderware)

默认实现,子类(如 CRenderDevice_Renderware)这是基类的默认实现,子类(如 CRenderDevice_Renderware)会在它的 OnCreate 中 先调用基类的 OnCreate,再做自己的渲染 API 初始化。 调用子类的OnCreate 一定会调用…

域名检测查询谷歌关键词优化怎么做

1. 什么是LTPA?Lightweight Third-Party Authentication (LTPA)是IBM Websphere和Domino产品中使用单点登录技术。当服务器配置好LTPA认证方式&#xff0c;用户通过浏览器成功登录后&#xff0c;服务器会自动发送一个session cookie给浏览器&#xff1b;此cookie中包含一个LTP…

Petrozavodsk Summer 2024. Day 1. Welcome Contest

Preface 整个国庆就训两天,摆烂这一块 这场感觉前期题里计数偏多,只能说毛子场是这样的;然后有人写 D 的时候猪脑过载,占了 90 min 机时导致队友早就会了的 B 没时间写,我不说是谁A. Adding Integers 把组合式子拆…

网站策划设计招聘西安网站建设行业

导航守卫 to 准备跳转到哪个页面 from 从哪个页面中离开 next 函数 全局守卫 router.beforeEach((to,from,next) > {if(to.path /login || to.path /register){    next();}else{    alert(先登录)    next(/login)} }) 组件守卫 data () {  return{   …

项目作业2

学生管理系统面向对象分析报告 目录案例中封装性的体现及其好处 setter/getter模式与封装性 部分类的toString()方法解析 常用方法解析 面向对象设计分析1. 案例中封装性的体现及其好处 (姓名:王鑫杰 学号:20242133…

构造函数跟析构函数默认自动调用其他的必须显示调用是吗

构造函数跟析构函数默认自动调用其他的必须显示调用是吗1. 构造函数 / 析构函数 这两个是 自动调用基类的:构造函数:当你创建子类对象时,会先自动调用基类构造函数,再调用子类构造函数。如果你不写,默认会调用基类…

财经大学网站建设建个企业营销型网站

摘要 美食网站是一个提供各种美食信息和食谱的网站&#xff0c;旨在帮助用户发现、学习和分享美食。旨在探讨美食网站在现代社会中的重要性和影响。随着互联网的普及&#xff0c;越来越多的人开始使用美食网站来获取各种美食信息和食谱。这些网站不仅提供了方便快捷的搜索功能&…

CRenderDevice

CRenderDevice为什么不用纯虚函数? 有几个可能的设计原因:保留默认行为如果有些函数在大多数情况下逻辑类似,可以在基类里写一个默认版本。子类只在必要时才重写,减少代码重复。允许实例化基类如果用纯虚函数,CRe…

如何使用 INFINI Gateway 对比 ES 索引数据

上一篇我们通过 极限网关(INFINI Gateway) 进行了索引数据迁移,对索引迁移结果进行了初步且直观的校验,既对比索引的文档数是否一致。今天介绍个实实在在的数据比对方法,通过网关对比索引文档的内容在两个集群是否…

实验一 html静态网站开发微服务网站

原文地址&#xff1a;Improving RAG: Self Querying Retrieval 2024 年 2 月 11 日 让我们来解决构建 RAG 系统时的一个大问题。 我们不能依赖语义搜索来完成每个检索任务。只有当我们追求单词的含义和意图时&#xff0c;语义搜索才有意义。 But in case&#xff0c;我们正…