【问题标题】:Mapping [-1,+1] floats to Q31 fixed-point将 [-1,+1] 浮点数映射到 Q31 定点
【发布时间】:2017-01-18 09:29:29
【问题描述】:

我需要将浮点数转换为 Q31 定点,Q31 表示 1 个符号位,0 位表示整数部分,31 位表示小数部分。这意味着Q31只能表示[-1,0.9999]范围内的数字。

根据定义,当从浮点数转换为定点数时,会乘以2ˇN,其中 N 是小数部分的大小,在本例中为 31。

但是,我对这段代码感到困惑,它看起来不正确,但有效:

#define q31_float_to_int(x) ( (int) ( (float)(x)*(float)0x7FFFFFFF ) )

而且它似乎工作正常。例如:

int a = q31_float_to_int(0.5f); 

给出Hex: 0x40000000,没关系。

为什么这里的乘法是用2ˇ31 - 1,而不仅仅是2ˇ31

【问题讨论】:

  • (float)0x7FFFFFFF2147483648.00000: ideone.com/mawlXx 。即使在转换为 unsigned 之后,该值仍然成立:ideone.com/7WMeRE
  • 嗯??为什么 0x7FFFFFFF 最终是 2147483648 而不是 2147483647??
  • 因为 2147483647 不能表示为 float,因此将采用最接近的可表示数字,即 2147483648。
  • 知道为什么上面的代码不使用(float)0x8000000而不是(float)0x7FFFFFFF吗?
  • 也许作者试图避免溢出和/或希望在INT_MAX0x7FFFFFFF 的架构上表达1.0 的值。不幸的是,这个解决方案不太可能成功正确。

标签: c signal-processing fixed-point


【解决方案1】:

上面的代码不是从浮点数转换为定点数的好方法。我猜写代码的人使用了0x7FFFFFFF 的比例因子来避免输入为1.0 时的溢出。正确的比例因子是2^31 而不是2^31 - 1。请注意,将float(精度为 24 位)转换为Q1.31(精度为 31 位)时也会出现精度问题。考虑在乘法之前使输入数据饱和:

const float Q31_MAX_F =  0x0.FFFFFFp0F;
const float Q31_MIN_F = -1.0F;
float clamped = fmaxf(fminf(input, Q31_MAX_F), Q31_MIN_F);

上面的代码会将input 限制在[-1.0, 1.0) 的范围内。考虑到 24 位精度,常数Q31_MAX_F 近似为1 - (2 ^ -24),而Q31_MIN_F-1。然后你可以将clamped 乘以2^31,或者更好的是,使用scalbnf,或者ldexpf

int result = (int) scalbnf(clamped, 31);

如果你想要四舍五入:

int result = (int) roundf(scalbnf(clamped, 31)));

【讨论】:

  • 为什么使用0x7FFFFF00.p-31F;而不是1下最大的float(0x7FFFFF80.p-31F;) 更好的是,便携:Q31_MAX_F = nextafterf(1.0,0.0); Q31_MIN_F = -1.0f;
  • round,建议int32_t result = (int32_t) lround(scalbnf(clamped, 31));
  • 谢谢。根据您的 cmets 更新。
  • 详细信息:“常数 Q31_MAX_F 是 1 - (2 ^ -24)”。典型的 float 具有 24 位精度。
  • 感谢指正。典型的IEEE754 single precision floating point 有 23 个尾数位,带有一个隐含的 MSB,它提供 24 位精度。
猜你喜欢
  • 2021-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
相关资源
最近更新 更多