有人可以向我解释这个算法如何在32位系统上将MSB转换为LSB或LSB到MSB?
unsigned char b = x;
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
我之前看到十六进制值以LU或代码U结尾,这是什么意思?
谢谢!
答案 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中。没有重叠,所以没有效果通过添加在更一般的乘法中重叠的位。
从这个产品,我们采取这些:
b
的第3位。 (从第1位开始的副本中的第4位,因此第4-1位= b
的第3位。)b
的第7位。 (8-1 = 7。)b
的第2位。 (13-11 = 2。)b
的第6位。 (17-11 = 6。)类似地,0x88440的掩码提取位6,10,15和19.乘以0x8020将b
的副本放在位5到12中,另一个副本放在位15到22中。来自此产品,我们采取这些:
b
的第1位。b
的第5位。b
的第0位。b
的第4位。然后我们或他们在一起,产生:
b
的第3位。b
的第1位。b
的第7位。b
的第5位。b
的第2位。b
的第0位。b
的第6位。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位。以这种方式推断所有位:
b
中的第8位,是t
中的第7位。b
中的第17位,是t
中的第6位。b
中的第10位,是t
中的第5位。b
中的第19位,是t
中的第4位。b
中的第4位,是t
中的第3位。b
中的第13位,是t
中的第2位。b
中的第6位,是t
中的第1位。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插入一些值(二进制)并跟随。