输入一个浮点数,直接看到它在 PLC 里到底长什么样;
也能反过来,把博图监视表里的40490FDB还原成数值。
版本 v1.0 · 2026-09-14
一、它解决什么问题
写 PLC 程序时,浮点数有三个地方会让你抓瞎:
- 通信抓包 / 监视表里只有十六进制,
40490FDB到底是几? - Modbus 读回来的两个寄存器(比如
0FDB4049)拼起来是乱码,不知道字序错没错。 - 程序里算出来的值和手算对不上,想确认是精度问题还是逻辑问题。
这个工具把这三种情况一次说清:给一个数,同时给出单精度和双精度的完整位模式;
给一个位模式或一对寄存器,反过来给出数值和四种字序的对照。
二、怎么用
双击 dist\浮点数位模式转换器.exe,输入框里敲内容,结果实时刷新,不用按按钮。
支持这些输入形式,程序自动识别:
| 你输入 | 它理解成 | 例子 |
|---|---|---|
| 十进制数 | 浮点数值 | 3.14159 -1.5e-8 0 inf nan |
0x 开头的 8/16 位 hex | 位模式(反向解析) | 0x40490FDB 0x400921FB54442D18 |
| 纯 8/16 位 hex | 同上 | 40490FDB 400921FB54442D18 |
| 32/64 位二进制串 | 位模式 | 0100 0000 0100 1001 0000 1111 1101 1011 |
| 两个十六进制数 | Modbus 寄存器对 | 0FDB 4049 |
输入框下拉里也能手动锁定格式,防止歧义。
点任意一个数值就能复制到剪贴板,状态栏会提示。
三、界面上的三个标签页
① 单精度 float32 (4 字节)
PLC 里 REAL 就是这个 —— 32 位,1 位符号 + 8 位指数 + 23 位尾数。
| 项目 | 怎么读 |
|---|---|
| 十六进制 | 位模式的 hex,跟博图监视表里看到的一致 |
| 二进制 | 完整 32 位,每 4 位一组 |
| 符号位 S | 0 = 正,1 = 负(只有 1 位,不是正负号字符) |
| 指数位 E | 8 位。真指数 = E − 127,这才是 2 的几次方 |
| 尾数位 M | 23 位。正常数隐含一个前导 1,即 1.M |
| 表达式 | 完整写法:(-1)^S × 1.M₂ × 2^(E−127) |
| 还原值 | 这个位模式实际代表的数(注意可能和输入有微小差异) |
| 数值类型 | 正常数 / 次正规数 / 零 / 无穷大 / NaN |
| 前一档 / 后一档 | 相邻可表示的浮点数 —— 看得出"精度台阶"有多宽 |
| ULP | 相邻两档的间距,也就是这个量级下的最小分辨率 |
| 当整数看 | 把同样的 32 位当 int32 解释是多少(写通信程序时会用到) |
② 双精度 float64 (8 字节)
1 位符号 + 11 位指数(偏置 1023)+ 52 位尾数。上位机、Modbus 浮点扩展用的多。
③ Modbus 寄存器
分两段:
第①段「位模式 → 寄存器摆放」
同一个 32 位值,4 个字节放进 2 个 16 位寄存器里的四种摆法:
| 名称 | 含义 |
|---|---|
| ABCD | 标准顺序(大端,高字在前) |
| CDAB | 字交换 —— 现场最常遇到的就是这个 |
| BADC | 字节交换 |
| DCBA | 全反转 |
第②段「寄存器 → 数值还原」
给定一对寄存器,按四种字序分别读回,各能得到什么数。
这一段是现场排错的主力:当四种结果里只有一种落在你的实际量程内,字序就确定了。
四、三个典型场景
场景 1:新增一个 REAL 常量,先核对位模式
输入 100.0 → 单精度十六进制 0x42C80000。
如果通信协议文档里写的是别的值,说明单位或者字节序理解错了。
场景 2:监视表里抓到 hex,想还原数值
输入 40490FDB → 直接得到 3.14159274,并告诉你它属于单精度正常数。
场景 3:Modbus 读回两个寄存器,数值离谱
假设你从设备读到寄存器 0FDB、4049,拼起来显示 2.16e-29,明显不对。
输入 0FDB 4049,Modbus 页第②段会给出:
读回 ABCD 0x0FDB4049 → 2.1619829e-29 ← 你现在看到的就是这个
读回 CDAB 0x40490FDB → 3.14159274 ← 正确的
读回 BADC 0xDB0F4940 → -4.03314609e+16
读回 DCBA 0x4940DB0F → 789936.938
结论:对方设备按 CDAB(字交换)存放 REAL,你的上位机按 ABCD 在读。
改一下上位机的字序设置,或者读回来先做一次高低字交换。
⚠ 注意:有时候两种字序解出来的值都像正常数(比如上面789936.9也可能是个合理的压力值)。
这时候不能只看数值大小,要结合工艺量程判断 —— 这是工具帮不了你的部分。
五、几个容易踩的坑
1. 3.14159 和 π 不是一个数
| 输入 | 单精度位模式 | 实际值 |
|---|---|---|
3.14159 | 40490FD0 | 3.14159012 |
3.141592653589793(π) | 40490FDB | 3.14159274 |
π 的位模式是 40490FDB 这个"常识"只对完整精度的 π 成立。你只写 6 位有效数字,舍入结果就不同。
2. 单精度只有约 7 位有效数字
0.1 在单精度里存的是 0.100000001490116...。这不是 bug,是二进制表示 0.1 的必然结果。
所以:别用浮点数比较相等,判断要用 |a−b| < ε。
3. 累加误差会跑
单精度下,一个大数加一个小数,小数可能被直接吃掉。累加 10000 次这种操作,误差是累积的。
对策:累加用双精度,或者用"先小后大"的排序策略。
4. NaN 和 Inf 会传染
一旦某次运算产生 NaN,后面所有涉及它的运算全是 NaN,而且永远出不来(NaN + x = NaN)。
加法溢出(超过 3.4e38)直接变 Inf。这两个值在 PLC 里都不罕见 —— 建议在模拟量入口做一次非法值检查。
5. Modbus 双字的字序没有统一标准
同一个厂商的不同型号都可能不一样。只能实测:给 PLC 写一个已知值(比如 100.0),读回来对照。100.0 的单精度是 0x42C80000,四种字序的结果都在工具的 Modbus 页里,一比就知道。
六、验证记录
程序的核心算法做了 305 项自动化校验,全部通过,脚本是 test_float_converter.py。
验证方式不是"我手写期望值然后自己对",而是:
- 与 C 语言语义交叉对照:用 Python 标准库
struct的打包结果作为黄金标准(它的行为与 C 的float/double完全一致),对 40 个边界/典型值逐个比对单精度和双精度位模式。 - 经典锚点:
1.0 → 3F800000、π → 40490FDB、0.1 → 3DCCCCCD等业界公认值单独再验一遍。 - 随机往返:3000 个随机 32 位模式,位模式 → 数值 → 位模式 必须回到原位。
- 闭环反解:程序生成的二进制串 / 十六进制串,喂回自己的解析器,必须得到原位模式。
- Modbus 字序互逆:
modbus_view与modbus_readback对任意位模式必须互逆。
跑一遍:
python test_float_converter.py
七、命令行模式(可选)
程序也支持带参数运行,直接输出文本报告:
浮点数位模式转换器.exe 3.14159
浮点数位模式转换器.exe 40490FDB
浮点数位模式转换器.exe "0FDB 4049"
输出通道会自动选择:
| 情况 | 结果去向 |
|---|---|
加了 --out <文件> | 写入指定文件(UTF-8) |
| 有控制台(用源码跑) | 打印到控制台 |
| 打包后的 exe,无控制台 | 弹出一个文本窗口,可直接选中复制 |
用 --out 可以脚本化调用,比如从自动化流程里批量换算:
浮点数位模式转换器.exe 3.14159 --out result.txt
浮点数位模式转换器.exe "0FDB 4049" --out result.txt
也可以直接用源码跑,不需要控制台窗口:
python float_converter.py 3.14159
python float_converter.py 0x40490FDB --out result.txt
八、目录里有什么
| 文件 | 说明 |
|---|---|
dist\浮点数位模式转换器.exe | 成品,双击就能用(10 MB,单文件免安装) |
float_converter.py | 源码(含图形界面 + 命令行 + 核心算法) |
test_float_converter.py | 305 项自动化校验脚本 |
make_icon.py | 图标生成脚本(纯标准库画的,不依赖 Pillow) |
app.ico | 程序图标 |
build/ dist/ FloatConverter.spec __pycache__/ | 打包中间产物,可删 |
依赖:无。tkinter 和 Python 运行时已全部打进 exe,目标机器不用装任何东西。
重新打包:
pip install pyinstaller
pyinstaller --noconfirm --onefile --windowed --clean ^
--name FloatConverter --icon app.ico float_converter.py
打包完成后把 dist\FloatConverter.exe 改个中文名即可。