当前位置:首页>java>嵌入式编程中的定点数

嵌入式编程中的定点数

  • 2026-08-25 00:15:50
嵌入式编程中的定点数

1. 概述 (Overview)

  • 定义:定点数是一种在二进制计算机架构上表示数字的方法。它允许像浮点数(float/double)一样存储带有小数点的数值,但计算速度更快。
  • 权衡:定点数的主要优势是计算时间更短(特别是在没有浮点运算单元FPU的硬件上),但代价是精度较低且灵活性不如浮点数。
  • 本质:普通整数其实是定点数的一个特例,即小数点位于最低有效位(LSB)的右侧。例如,32位无符号整数可以看作是 fp(32, 0)。
  • 编程支持:大多数编程语言和硬件本身不直接支持定点数数据类型(虽然有第三方库)。C++ 相比 C 语言的优势在于支持运算符重载,可以编写类库让定点数的加减乘除像原生类型一样直观。

2. 表示法 (Notation)

  • 文章使用 Q记法(Q-format)来描述定点数:。
    • :整数位(integer bits)的数量。
    • :小数位(fractional bits)的数量。
  • 示例: 代表一个32位的定点数,其中24位用于整数部分,8位用于小数部分。

3. 软件存储方式 (How We Store Them In Software)

  • 定点数在软件底层是直接作为常规整数(signed 或 unsigned)存储的。
  • 原理:数值被缩放了  倍。
  • 示例:在  格式(16位)中存储数值 6.5:
    • 计算:
    • 存储:内存中存储的整数值为 26624(二进制 0110 1000 0000 0000)。
    • 高4位是整数部分(6 -> 0110),低12位是小数部分(0.5 -> 1000...)。

4. 范围与精度 (Range & Precision)

  • 范围 (Range):
    • 例: (8位) 范围是 -16 到 15.875。
    • 例: (8位) 范围是 0 到 31.875。
    • 无符号: 到 。
    • 有符号: 到 。
  • 精度 (Precision):
    • 完全由小数位数  决定,精度等于 (即最小可表示的非零值)。
    • 例: 的精度是 。

5. 类型转换 (Converting To Fixed-Point)

  • 整数转定点数:
    • 方法:将整数左移  位。
    • 代码:rawVal = integer << numFracBits;
  • 浮点数(Double)转定点数:
    • 方法:将浮点数乘以缩放因子 (即 1 << f),然后强制转换为整数。
    • 代码:return (int32_t)(f * (double)(1 << q));

6. 定点数数学运算 (Mathematical Operations)

定点数运算本质上是整数运算,但在乘除法时需要处理缩放因子。

A. 加法与减法 (Adding/Subtracting)

  • 相同精度:直接相加减,无需额外处理。
    • 注意:结果需要多一位整数位以防溢出。
  • 不同精度:必须通过位移操作将其中一个数转换为与另一个数相同的精度(通常会有精度损失或溢出风险),然后再相加。

B. 乘法 (Multiplying)

  • 结果位宽:两个定点数相乘,结果的整数位和小数位分别是两个操作数对应位数的和。
  • 溢出风险:直接相乘容易导致中间结果溢出。
  • 解决方案:
    1. 将操作数转换为更宽的类型(如两个 int32_t 相乘,先强转为 int64_t)。
    2. 执行乘法。
    3. 将结果右移  位(假设需要恢复到原来的小数位数)。
    4. 代码示例:int32_t res = ((int64_t)fp1 * fp2) >> 24;

C. 除法 (Division)

  • 原理:类似于乘法,需要调整缩放因子。直接除法会丢失小数部分。
  • 步骤:
    1. 将被除数(fp1)左移 位()。
    2. 除以除数(fp2)。
    3. 结果即为由于定点数格式。
  • 溢出注意:左移操作可能导致溢出,同样建议使用更大的整数类型(如 int64_t)作为中间存储。

D. 取模 (Modulus)

  • 如果两个定点数的小数位数相同,直接对底层整数进行取模运算即可(% 运算符)。
  • 结果是正确的,例如 7.0 % 3.0 在定点数表示下直接运算会得到 1.0。

E. 倒数 (Inverse)

  • 求倒数即计算 。
  • 可以通过标准的定点除法实现:将数字 1 转换为定点格式(左移  位),然后再应用除法逻辑,或者直接理解为 (1 << (2*f)) / fp_val。

7. 浮点代码转换到定点代码的注意点

  • 分析各环节所需最小精度,确定好精度要求并且做好精度控制
    • 保持中间结果的高精度(使用更宽的数据类型)

    • 只在最终输出时进行舍入

    • 使用舍入而非截断减少误差

  • 确定信号的最大值和最小值,评估好变量的动态范围
  • 渐进式迁移:逐个模块替换,确保每个模块正确后再继续

  • 保持两种实现:在验证阶段保持浮点和定点双版本

最新文章

随机文章