我希望分别将32位值的位0,8,16,24移动到位0,1,2,3。输入和输出中的所有其他位都将为零。重新分配字节数组中的位来设置位
很显然,我能做到这一点是这样的:
c = c>>21 + c>>14 + c>>7 + c;
c &= 0xF;
但有一个更快(较少的指令)的方式?
我希望分别将32位值的位0,8,16,24移动到位0,1,2,3。输入和输出中的所有其他位都将为零。重新分配字节数组中的位来设置位
很显然,我能做到这一点是这样的:
c = c>>21 + c>>14 + c>>7 + c;
c &= 0xF;
但有一个更快(较少的指令)的方式?
c = (((c&BITS_0_8_16_24) * BITS_0_7_14_21) >> 21) & 0xF;
,或者等待英特尔的Haswell处理器,做这一切在一条指令(PEXT)。
更新
考虑到clarified constraints
和假设32-bit unsigned values
,代码可以简化成这样:
c = (c * BITS_7_14_21_28) >> 28;
如果你不关心可移植性,并且可以使用SSE指令,看看在PMOVMSKB指令和它的编译器内在。 [我注意到,您的位位置是包含32位字的4个字节的最重要(符号)位。]
而不是编写一些混淆的单行goo,下面的代码是我要写的最大的便携性和可维护性。我会让优化器担心它是否是最有效的代码。
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
#define BITS_TO_MOVE 4
static const uint32_t OLD_MASK [BITS_TO_MOVE] =
{
0x0008u,
0x0080u,
0x0800u,
0x8000u
};
static const uint32_t NEW_MASK [BITS_TO_MOVE] =
{
0x1000u,
0x2000u,
0x4000u,
0x8000u
};
int main()
{
uint32_t c = 0xAAAAu;
uint32_t new_c = 0;
uint8_t i;
printf("%.4X\n", c);
for(i=0; i<BITS_TO_MOVE; i++)
{
if ((c & OLD_MASK[i]) > 0)
{
new_c |= NEW_MASK[i];
}
}
printf("%.4X\n", new_c);
getchar();
return 0;
}
优化器很智能,但不够智能,无法用单条指令代替位提取代码。 “可移植性”是一个有争议的问题:除非您知道代码必须在多个CPU平台上运行,否则不必担心。 – zvrba 2012-01-10 15:42:01
@zvrba你永远不会重用你在其他项目中编写的旧代码吗?此外,关于性能也可以这样说,除非您知道这是必要的,否则您不必打扰它。我认为上面的代码将“足够快”,也许不是一个单一的指令,但也不会比3-4更糟糕。取决于当然的CPU类型。 – Lundin 2012-01-10 21:58:45
重复使用?这取决于。 OP特别询问了比他的例子更快的方式,并且你给了他更长的时间,可能更慢。 – zvrba 2012-01-11 08:26:02
首先,你的代码并没有按照你的要求去做,因为'c'中还有其他的位会被加入。其次,你正在计数错误的方式。最右边的(最小值)位编号为0. – Lindydancer 2012-01-10 11:59:12
谢谢,我已经改变了位的顺序。 – Dijkstra 2012-01-10 14:41:11
我已经阐明了约束条件,所以我认为现在的代码有效:) – Dijkstra 2012-01-10 14:46:44