示例:a = 11010 0 01,b = 0001 0 01,c = 11010 0 00,d = 11111 1 11
extract(a,b,c,d,2)== 0001
答案 0 :(得分:1)
尝试使用
无符号__int64 _pext_u64(无符号__int64 a,无符号__int64掩码)
命令,尽管它不使用多个整数。
还有其他使用AND和可变SHIFT(以及其他命令)的方法。
答案 1 :(得分:1)
此算法不是最佳算法,因为32位寄存器的填充是串行完成的。但是,你应该得到要点。 BMI2指令集中的PEXT instruction
可以有效地做到这一点。
这是MASM x86汇编中的解决方案(a,b,c,d是内存中的BYTE值):
mov ah, a
mov al, b
shl eax, 16
mov ah, c
mov al, d
; Now EAX = aaaaaaaabbbbbbbbccccccccdddddddd
mov ecx, 0b00000100000001000000010000000100 ; MASK value
pext eax, eax, ecx
; Now EAX = 00000000000000000000000000000001 ; result
为实际使用,请优化32位源寄存器(此处为EAX
)的填充。
现在EAX
的最低4位应包含0001
。
答案 2 :(得分:1)
有两种情况:1.感兴趣的位置是一个编译时常量,而2。 感兴趣的位置不是编译时常量。两种情况都被回答 在下面的代码中。
请注意,如果a,b,c,d在内存中是连续的,则只需将它们移动到xmm
由x = _mm_load_si128((_m128i*) &d);
注册,这比有效得多
_mm_set_epi32()
在这里使用。
代码:
/* gcc -O3 -m64 -Wall -march=broadwell extract_2nd_bit.c */
#include <immintrin.h>
#include <stdio.h>
/* If position i = 2 (for axample) is known at compile time: */
int extract_2nd_bit(int a, int b, int c, int d){
__m128i x = _mm_set_epi32(a, b, c, d);
x = _mm_slli_epi32(x, 31 - 2); /* shift bit 2 to the highest position */
return _mm_movemask_ps(_mm_castsi128_ps(x)); /* extract the MSB of the 4 elements */
}
/* If position i is unknown at compile time: */
int extract_var(int a, int b, int c, int d, int i){
__m128i x = _mm_set_epi32(a, b, c, d);
x = _mm_sll_epi32(x, _mm_cvtsi32_si128(31 - i)); /* shift bit i to the highest position */
return _mm_movemask_ps(_mm_castsi128_ps(x)); /* extract the MSB of the 4 elements */
}
int print_32_bin(unsigned int x);
int main(){
int a = 0b11010001;
int b = 0b0001001;
int c = 0b11010000;
int d = 0b11111111;
int pos = 2;
print_32_bin(extract_2nd_bit(a, b, c, d));
print_32_bin(extract_var(a, b, c, d, pos));
return 0;
}
int print_32_bin(unsigned int x){
for (int i=31;i>=0;i--){
printf("%1u",((x>>i)&1));
}
printf("\n");
return 0;
}
输出为:
$ ./a.out
00000000000000000000000000000001
00000000000000000000000000000001
顺便问一下,为什么不在问题中设置avx
或sse
标签?