如何将4字节IEEE754浮点数转换为16位F2 BGN格式?
F2 BGN 16位格式反向转换方法(IEEE 754单精度浮点数转F2 BGN)
转换逻辑推导
基于你给出的正向转换公式变形:
正向公式:float_val = (mantissa / (2^10)) * 2^(15 - gain),简化后为 float_val = mantissa * 2^(5 - gain)
其中参数定义:
- 16位F2 BGN的位分配:
[1位符号位][11位无符号振幅值][4位无符号增益值],你提到的mantissa为高12位,实际是符号位+11位振幅值的组合 - 增益gain取值范围为0~15(4位无符号整数)
- 振幅值取值范围为0~2047(11位无符号整数)
具体转换步骤
- 第一步:处理特殊值
- 输入为0时,直接输出16位全0即可
- 输入为NaN、无穷大时,可根据业务需求钳位到F2 BGN的最大/最小可表示值,地震数据场景下这类值出现概率极低
- 第二步:提取符号位
- 若输入浮点数为负,符号位
s = 1,否则s = 0,取输入的绝对值记为abs_val
- 若输入浮点数为负,符号位
- 第三步:计算最优增益值
为最大化转换精度,需让振幅值尽可能落在[1024, 2047]区间(类似浮点数规格化,利用全部11位精度):- 计算
exponent = floor(log2(abs_val)) - 推导得最优gain:
gain = 15 - exponent - 对gain做范围钳位:
gain = max(0, min(15, gain))
- 计算
- 第四步:计算振幅值
- 计算缩放因子:
scale = pow(2, gain -5) - 振幅值:
amplitude = round(abs_val * scale) - 对振幅做范围钳位:
amplitude = max(0, min(2047, amplitude))
- 计算缩放因子:
- 第五步:拼接16位结果
uint16_t f2bgn = (s << 15) | ((amplitude & 0x7FF) << 4) | (gain & 0xF);
C++ 实现示例
#include <cmath> #include <cstdint> #include <algorithm> uint16_t float_to_f2bgn(float val) { // 处理0值 if (val == 0.0f) { return 0; } // 提取符号位 uint16_t s = 0; float abs_val = val; if (val < 0) { s = 1; abs_val = -val; } // 计算指数 int exponent = 0; frexp(abs_val, &exponent); exponent -= 1; // 计算增益并钳位 int gain = 15 - exponent; gain = std::max(0, std::min(15, gain)); // 计算振幅并钳位 float scale = std::pow(2, gain - 5); uint32_t amplitude = std::lround(abs_val * scale); amplitude = std::max(0U, std::min(2047U, amplitude)); // 拼接结果 return (s << 15) | ((amplitude & 0x7FF) << 4) | (gain & 0xF); }
注意事项
- 代码中默认使用四舍五入取整,若你的业务场景需要截断/向下取整,可把
std::lround替换为std::trunc/std::floor - 最大可表示的正数值为
2047 * pow(2,5-0) = 65504,超过该值的输入会被钳位到最大值 - 最小可表示的正数值为
1 * pow(2,5-15) = 1/1024 ≈ 0.0009765625,小于该值的输入会被钳位到0
内容的提问来源于stack exchange,提问作者Dmitriy
相关产品推荐
相关产品推荐

