映射 [-1,+1] 浮点数到 Q31 定点
Mapping [-1,+1] floats to Q31 fixed-point
我需要将浮点数转换为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
?
上面的代码不是将浮点数转换为定点数的好方法。我猜编写代码的人使用 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)
的范围内。常数Q31_MAX_F
近似1 - (2 ^ -24)
,考虑到24位精度,Q31_MIN_F
是-1
。然后你可以将 clamped
乘以 2^31
,或者更好,使用 scalbnf, or ldexpf:
int result = (int) scalbnf(clamped, 31);
如果你想四舍五入:
int result = (int) roundf(scalbnf(clamped, 31)));
我需要将浮点数转换为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
?
上面的代码不是将浮点数转换为定点数的好方法。我猜编写代码的人使用 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)
的范围内。常数Q31_MAX_F
近似1 - (2 ^ -24)
,考虑到24位精度,Q31_MIN_F
是-1
。然后你可以将 clamped
乘以 2^31
,或者更好,使用 scalbnf, or ldexpf:
int result = (int) scalbnf(clamped, 31);
如果你想四舍五入:
int result = (int) roundf(scalbnf(clamped, 31)));