Dev tool

Q 格式定点数转换

没有 FPU 的芯片上,小数是这样存的:乘 2ⁿ 取整。输入十进制或定点码, 看分辨力、范围、量化误差,以及溢出时会发生什么。

格式
当前格式 — —
1 LSB 分辨力 — —
最大值 — —
最小值 — —
双向转换 两边都可以直接输入

十进制 → 定点码

定点码(hex) —
定点码(bin) —
实际表示值 —
量化误差 —
已饱和:输入超出范围,已钳位

定点码 → 十进制

支持 0x / 0b / 0o 前缀和十进制,下划线分隔可读性更好
十进制值 —
原始码(二补码) —
位模式 —
符号位 整数位 小数位
对应的 C 代码

30 秒看懂 Q 格式

一个 16 位寄存器想存 0.3,芯片上没有浮点单元怎么办?把刻度打密一点: 规定小数点固定在 bit15 和 bit14 之间(1 位符号 + 15 位小数,就是 Q15), 存 round(0.3 × 32768) = 9830。读出来再乘 1/32768,得到 0.29998779296875—— 差的那 0.0000122,就是量化误差,最多半个 LSB。

所以 Q 格式的一切参数都能从两个数字推出来:小数位 n 决定分辨力(1 LSB = 2⁻ⁿ), 总位宽减去小数位决定范围。n 给得越多,0.3 越准,但能表示的上限越小—— Q15 连 1.0 都存不下(会饱和到 0.999969),这就是范围和精度之间的交换。

和浮点转换器是什么关系

浮点的小数点是浮动的,靠指数换来动态范围;定点的小数点是焊死的,换来的是简单和确定性。 如果你在做的是 DSP 循环、电机控制、或者把模型权重搬到没有 FPU 的 MCU 上, 用的是这个工具;如果在看 AI 推理引擎的 FP16 / BF16,用 浮点数转换。两者底层都是「比特怎么解释成数」,可以对照着看。

常见问题

Q15、Q0.15、s1.15 是同一个东西吗?

是。都是 16 位、1 个符号位加 15 个小数位,只是叫法不同:TI 手册写 Q15,ARM 手册写 Q0.15,DSP 手册常写 s1.15。本工具统一用 Qm.n:1 个符号位、m 个整数位、n 个小数位,总位宽 = m + n + 1;无符号格式写成 uQm.n。

为什么 0.3 存进去再读出来会差一点点?

定点数只能表示 2^-n 的整数倍,而 0.3 在二进制里是无限循环小数。Q15 下最近的可用值是 9830/32768 = 0.29998779296875,差了约 0.4 个 LSB。这叫量化误差,四舍五入时不超过半个 LSB,且存读多少遍都不会自己消失。

溢出时应该饱和还是回绕?

看语义。饱和(本工具的处理方式)把结果钳到最大或最小值,适合音频、电机这类「超了就顶住」的物理量;回绕(C 里的自然溢出)会让 0.9999 加 0.0002 变成接近 -1 的数,在信号处理里通常是灾难。DSP 一般有专门的饱和指令,通用 CPU 上要自己写 if。

定点乘法为什么不能直接乘完就用?

两个 Qm.n 相乘,小数位会翻倍:Q15 乘 Q15 得到 Q30,要再右移 15 位才是 Q15。而且 16×16 位的完整乘积有 32 位,中间结果必须放进双倍位宽的变量,比如 int32_t c = (int32_t)(((int64_t)a * b) >> 15)。在 16 位平台上直接写 a * b >> 15 会先溢出再移位,结果就错了。

什么时候用定点,什么时候用浮点?

芯片没有 FPU 时,定点快一个数量级;需要逐位可复现(不同编译器浮点结果可能不同)时定点占优;量程动态范围大,比如 0.001 和 100000 同时出现时,浮点更合适。现代 MCU 大多带 FPU,新项目可以优先浮点;定点主要留在 DSP、电机控制和老的音频通路里。