C MSB到LSB的解释

时间:2013-08-21 22:41:10

标签: c bit-shift

有人可以向我解释这个算法如何在32位系统上将MSB转换为LSB或LSB到MSB?

unsigned char b = x;
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;

我之前看到十六进制值以LU或代码U结尾,这是什么意思?

谢谢!

4 个答案:

答案 0 :(得分:3)

据推测,char有8位,因此unsigned char b = x取x的低8位。

具有0x22110的掩码提取位4,8,13和17(从最低有效位开始编号为0)。因此,在乘以0x0802时,我们只关心它在这些位上的位置。在0x802中,位1和11打开,因此该乘法将位{1}的8位复制到位1到8,将另一位复制到位11到18中。没有重叠,所以没有效果通过添加在更一般的乘法中重叠的位。

从这个产品,我们采取这些:

  • 第4位,是b的第3位。 (从第1位开始的副本中的第4位,因此第4-1位= b的第3位。)
  • 位8,是b的第7位。 (8-1 = 7。)
  • 位13,它是b的第2位。 (13-11 = 2。)
  • 位17,是b的第6位。 (17-11 = 6。)

类似地,0x88440的掩码提取位6,10,15和19.乘以0x8020将b的副本放在位5到12中,另一个副本放在位15到22中。来自此产品,我们采取这些:

  • 第6位,是b的第1位。
  • 位10,是b的第5位。
  • 第15位,是b的第0位。
  • 第19位,是b的第4位。

然后我们或他们在一起,产生:

  • 第4位,是b的第3位。
  • 第6位,是b的第1位。
  • 位8,是b的第7位。
  • 位10,是b的第5位。
  • 第13位,是b的第2位。
  • 第15位,是b的第0位。
  • 第17位,是b的第6位。
  • 第19位,是b的第4位。

调用此结果b

我们将乘以0x10101,右移16,并分配给t。赋值转换为b,因此只保留低8位。移位后的低8位是移位之前的位24到31。所以我们只关心产品中的第24到31位。

乘法器0x10101设置了位0,8和16。因此,结果中的位24是unsigned char中的位24,16和8的总和,加上来自其他地方的任何进位。但是,没有进位:观察到t中的任何设置位都不是8,因为乘法器中的位是。因此,它们都不能直接促成产品中的相同位。产品中的每个位都是t中最多一位的结果。我们只需要弄清楚是哪一位。

位24必须来自t中的第8,16或24位。只能设置第8位,它是t的第7位。以这种方式推断所有位:

  • 位24是b中的第8位,是t中的第7位。
  • 第25位是b中的第17位,是t中的第6位。
  • 第26位是b中的第10位,是t中的第5位。
  • 位27是b中的第19位,是t中的第4位。
  • 位28是b中的第4位,是t中的第3位。
  • 第29位是b中的第13位,是t中的第2位。
  • 位30是b中的第6位,是t中的第1位。
  • 位31是b中的位15,位于t中的位0。

因此,乘积中的第24到31位是b中的第7位到第0位,因此最终生成的8位是b中的第7位到第0位。

答案 1 :(得分:2)

将b视为8位值abcdefgh,其中每个字母都是单个位(0或1),a是最高有效位,h是最低有效位。然后看看每个操作对这些位的作用:

b * 0x0802LU             = 00000abcdefgh00abcdefgh0 
b * 0x0802LU & 0x22110LU = 000000b000f0000a000e0000
b * 0x8020LU             = 0abcdefgh00abcdefgh00000
b * 0x8020LU & 0x88440LU = 0000d000h0000c000g000000
((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU))
                         = 0000d0b0h0f00c0a0g0e0000

所以在这一点上,它已经改变了位并将它们展开。

(....) * 0x10101LU       =                 d0b0h0f00c0a0g0e0000
                         +         d0b0h0f00c0a0g0e000000000000
                         + d0b0h0f00c0a0g0e00000000000000000000
                         = d0b0f0f0dcbahgfedcbahgfe0c0a0g0e0000
(...) * 0x10101LU >> 16  = d0b0f0f0dcbahgfedcba
b                        = hgfedcba

乘法等于shift / add / add(在常量中设置3位),它将它们应该结束的位排成一行。然后最后一次移位并减少到8位,为您提供最终的位反转结果。

答案 2 :(得分:0)

要回答第二个问题,u表示将十六进制常量视为无符号(如果需要将其扩展为更宽的宽度),l表示将其视为{ {1}}。

我正在处理你的第一个问题。

答案 3 :(得分:0)

当您将此算法视为乘法和十六进制时,很难看到此算法正在执行的操作。将它转换为二进制并将乘法替换为等效的移位操作总和时,会变得更加清晰。基本上它正在做的是通过移动和屏蔽它来扩展部分字节,然后实现一个并行的半加法器来重建部分,这恰好与它们开始的位置相反。

例如,

b * 0x0802 = b << 11 | b << 1

为b插入一些值(二进制)并跟随。