4バイトのアレイからニブルに最小重要なビットを再配布する
-
25-10-2019 - |
質問
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;
または、Intel Haswellプロセッサを待って、これをすべて1つの命令(PEXT)で行います。
アップデート
考慮に入れて clarified constraints
と仮定します 32-bit unsigned values
, 、コードはこれに簡素化される場合があります。
c = (c * BITS_7_14_21_28) >> 28;
他のヒント
携帯性を気にせず、SSEの指示を使用できる場合は、 pmovmskb 命令とそのコンパイラ固有のコンパイラ。 [あなたのビット位置が、32ビットワードを含む4バイトの最も重要な(サイン)ビットであることに気付きました。
難読化された1行のGooを書く代わりに、最大限のポータビリティと保守性のために、以下のコードは私が書くものです。 Optimizerに、それが最も効果的なコードであるかどうかを心配させます。
#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;
}
所属していません StackOverflow