扩展 Pascal Cuoq 的想法,这里有一个解释。
一般的想法是,在任何基数中,如果任何数字除以(基数-1),余数将是该数字中所有数字的总和。
例如,34 除以 9 后余数为 7。这是因为 34 可以写成 3 * 10 + 4
即 34 = 3 * 10 + 4 = 3 * (9 +1) + 4 = 3 * 9 + (3 +4)
现在,9 除以 3 * 9,余数为 (3 + 4)。这个过程可以扩展到任何基数'b',因为 (b^n - 1) 总是除以 (b-1)。
现在,问题来了,如果一个数字以 1024 为基数,如果该数字除以 1023,则余数将是其数字的总和。
要将二进制数转换为基数 1024,我们可以将右侧的 10 位分组为单个数字
例如,要将二进制数 0x010884422010(0b10000100010000100010000100010000000010000) 转换为基数 1024,我们可以将其分组为 10 位数字,如下所示
(1) (0000100010) (0001000100) (0010001000) (0000010000) =
(0b0000000001)*1024^4 + (0b0000100010)*1024^3 + (0b0001000100)*1024^2 + (0b0010001000)*1024^1 + (0b0000010000)*1024^0
因此,当这个数字除以 1023 时,余数的总和为
0b0000000001
+ 0b0000100010
+ 0b0001000100
+ 0b0010001000
+ 0b0000010000
--------------------
0b0011111111
如果您仔细观察上述数字,则上述每个数字中的“1”位占据互补位置。因此,当加在一起时,它应该拉出原始数字中的所有 8 位。
因此,在上面的代码中, , 创建了字节“ a"a * 0x000202020202"
”的 5 个副本。当结果与 进行 AND 运算时,我们有选择地在“ a ”的 5 个副本中选择 8 位。当应用“ ”时,我们拉出所有 8 位。0x010884422010
% 1023
那么,它实际上是如何反转位的呢?这有点聪明。这个想法是,数字 0b0000000001 中的“1”位实际上与原始字节的 MSB 对齐。因此,当您“与”时,您实际上是在将原始字节的 MSB 与幻数数字的 LSB 进行与运算。类似地,数字 0b0000100010 与 MSB 的第二和第六位对齐,依此类推。
因此,当您添加幻数的所有数字时,生成的数字将与原始字节相反。