了解定点小数部分

Understanding Fixed-point fractional part

所以我正在努力思考定点数。到目前为止,一切都很好。唯一让我感到困惑的是数字的 'fractional' 部分。

我对定点数的理解是它根据小数位数(在本例中等于八位)拆分二进制数。左边是整数部分,分数在右边。 XXX.Y 其中XXX是integer/whole部分的三个字节,Y是小数部分的一个字节(如有错误请指正)

让我们采用以下宏:

#define FIX_SCALE 8
#define FIX_FRACTION_MASK ((1 << FIX_SCALE) - 1)
#define FIX_WHOLE_MASK ~FIX_FRACTION_MASK
#define FIX_FROM_FLOAT(X) ((X) * (1 << FIX_SCALE))
#define FIX_TO_FLOAT(X) ((float)(X) / (1 << FIX_SCALE))
#define FIX_TO_INT(X) ((X) >> FIX_SCALE)
#define FIX_FROM_INT(X) ((X) << FIX_SCALE)
#define FIX_FRACTION(X) ((X) & FIX_FRACTION_MASK)
#define FIX_WHOLE(X) ((X) & FIX_WHOLE_MASK)

考虑以下示例:

int Fixed = FIX_FROM_FLOAT(2.5f);

生成的整数值为 640,十六进制为 0x280,二进制为 0000 0000 0000 0000 0000 0010 1000 0000

我们取前两个字节:0000 0010 1000 0000

我知道 0000 0010 的来源,它是整数部分 (2)。但我没有得到的是 1000 0000 这是小数部分。我只是不明白这与数字 5(二进制为 0101)有何关系。我本以为 0101 00000000 0101 之类的东西——显然我误解了这里的一个基本概念。

如果我写:

int Fraction = FIX_FRACTION(Fixed);

我会得到 128(十六进制的 0x80。有意义因为它屏蔽了 2 的整数部分)。我第一次写这篇文章时,我希望得到 5 回复。

如果我写:

,我会得到 0.5
float Fraction = FIX_TO_FLOAT(FIX_FRACTION(Fixed));

有人可以帮我解决这个困惑吗?为什么分数0000 1000里面没有任何101?为什么我们必须在 FIX_FRACTION 上执行 FIX_TO_FLOAT 以获得正确的分数?

谢谢。

. 右边的二进制值。是 1/2 1/4 1/8 等 因此 10.1 二进制是 2.5

比较十进制和二进制表示形式的数字模式不起作用。 让我们暂时忘掉定点数,看看 5 和 50 的二进制表示:

 5: 0000'0101
50: 0011'0010

如您所见,在十进制 50 的二进制表示中也找不到十进制 5 的二进制模式。

现在要理解为什么十进制0.5在Q23.8二进制中是..00'1000'0000,需要遵循二进制转十进制的规则:

将每个1替换为2^position,然后将数字相加

position:      7 6 5 4  3 2 1 0  -1-2-3-4 -5-6-7-8
binary number: 0 0 0 0  0 0 1 0 . 1 0 0 0  0 0 0 0

2^1 + 2^-1 = 2 + 0.5 = 2.5

整数代表10的不同次方:

(source)

所以 10203 = 1×10000 + 0×1000 + 2×100 + 0×10 + 3×1

小数延续这种模式,代表 10 的负次方:

所以 0.10203 = 1/10 + 0/100 + 2/1000 + 0/10000 + 3/100000

小数2.5在2s列有一个“2”,在1/10ths列有一个“5”,所以总和是2×1 + 5/10

二进制定点的工作方式完全相同,除了 2 的幂而不是 10 的幂。整数部分是 1s 列、2s 列、4s 列、8s 列等,小数部分是1/2 列、1/4 列、1/8 列等

例如,如果数字是4.4格式,其中第一个半字节是无符号整数部分,第二个半字节是小数部分,对于二进制数1010 1001,整​​数部分表示

1×8 + 0×4 + 1×2 + 0×1

小数部分代表

1/2 + 0/4 + 0/8 + 1/16

所以十进制等价物是

1×8 + 0×4 + 1×2 + 0×1 + 1/2 + 0/4 + 0/8 + 1/16

= 10.5625

签名版本类似:

(source)

所以在你的二进制格式中,2.5 是 0b0000 0010 1000 0000,第一个字节在 2s 列中有 1,在 1s 列中有 0,所以它是

... + 0×4 + 1×2 + 0×1 + 1/2 + 0/4 + 0/8 + ...