我希望分別將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