c:位反转逻辑

时间:2013-08-02 07:02:41

标签: c bit-manipulation

我正在查看下面的位反转代码,只是想知道如何提出这些事情。 (来源:http://www.cl.cam.ac.uk/~am21/hakmemc.html

/* reverse 8 bits (Schroeppel) */
unsigned reverse_8bits(unsigned41 a) {
  return ((a * 0x000202020202)  /* 5 copies in 40 bits */
             & 0x010884422010)  /* where bits coincide with reverse repeated base 2^10 */
                                /* PDP-10: 041(6 bits):020420420020(35 bits) */
             % 1023;            /* casting out 2^10 - 1's */
}

有人能解释一下评论“哪里的位与反向重复基数2 ^ 10”意味着什么? 另外“%1023”如何拉出相关位?这有什么一般的想法吗?

2 个答案:

答案 0 :(得分:3)

这是一个非常广泛的问题。

以下是% 1023可能涉及的内容的解释:您知道计算n % 9如何将n的基数10表示的数字相加?例如,52%9 = 7 = 5 + 2。 您的问题中的代码使用1023 = 1024 - 1而不是9 = 10 - 1执行相同的操作。它使用操作% 1023来收集已经“独立”计算为10位切片的多个结果大量的。

这是关于如何选择常量0x0002020202020x010884422010的线索的开始:它们使宽整数运算作为大数10位切片上的独立简单运算运行。

答案 1 :(得分:1)

扩展Pascal Cuoq的想法,这是一个解释。

一般的想法是,在任何基础中,如果任何数字除以( base -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 * 0x000202020202"中,创建了5个字节“ a ”的副本。当结果与0x010884422010进行AND运算时,我们会在“ a ”的5个副本中有选择地选择8位。当应用“% 1023”时,我们将所有8位拉。

那么,它实际上如何反转位?那有点聪明。这个想法是,数字0b0000000001中的“1”位实际上与原始字节的MSB对齐。所以,当你“和”并且你实际上正在使用幻数位数的LSB对原始字节的MSB进行AND运算。类似于数字0b0000100010与来自MSB的第二和第六位对齐,依此类推。

因此,当您添加幻数的所有数字时,结果数字将与原始字节相反。