了解定点小数部分
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 0000
或 0000 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 + ...
所以我正在努力思考定点数。到目前为止,一切都很好。唯一让我感到困惑的是数字的 '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 0000
或 0000 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的不同次方:
所以 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
签名版本类似:
所以在你的二进制格式中,2.5 是 0b0000 0010 1000 0000
,第一个字节在 2s 列中有 1,在 1s 列中有 0,所以它是
... + 0×4 + 1×2 + 0×1 + 1/2 + 0/4 + 0/8 + ...