当前位置: 首页 > news >正文

IEEE754浮点格式与解析

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.hskmm.com/?act=detail&tid=26411

相关文章:

  • 国庆 Day3 强基数学
  • Petrozavodsk Summer 2024. Day 1. Welcome Contest
  • 项目作业2
  • 如何使用 INFINI Gateway 对比 ES 索引数据
  • Ambari安装Hadoop
  • Ambari-bigtop搭建hadoop数据仓库架构
  • 安装Ambari集群
  • Python中的`namedtuple`:命名元组的用法与优势
  • 我的首页
  • 一摞python风格的纸牌
  • 记录一个ubuntu24.04蓝牙不显示不可用的解决方案
  • AI时代需要重新定义投资回报评估模型
  • MOVEit网络攻击波及普华永道与安永,供应链安全再响警钟
  • shell编程
  • Penchick Online Mathematical Olympiad, Qualifying Test 1, III.4
  • QBXT2025S刷题 Day6
  • CF2145 Educational Codeforces Round 183 (Rated for Div. 2) 游记
  • 52个AI工具
  • 可观测专题【左扬精讲】——《Go 语言实现企业级 APM 监控系统实战:从 0 到 1 搭建高性能监控平台》
  • 多区域多 VLAN 网络搭建与访问控制及服务器部署实验
  • Tina_Linux_系统软件 开发指南
  • 2025方钢、扁钢、圆钢、光轴、六角钢、异型钢、冷拉/冷拔方钢、冷拉/冷拔扁钢、冷拉/冷拔圆钢、冷拉/冷拔六角钢、冷拉/冷拔异型钢、热轧方钢/扁钢厂家权威推荐榜:坚固耐用与精准定制口碑之选
  • GO_基础2
  • LDO(一)FVF型LDO
  • 详细介绍:进阶智能体实战九、图文需求分析助手(ChatGpt多模态版)(帮你生成 模块划分+页面+表设计、状态机、工作流、ER模型)
  • 09. 常用控件
  • 201007
  • 苍穹外卖第一天(Maven、Git、Nginx反向代理)
  • Python中的数据结构
  • 2025家纺摄影公司/南通摄影公司权威推荐榜:创意拍摄与专业服务的口碑之选