使用位操作将8字节数字中的每个字节中的一位转换为单个字节
Use bit manipulation to convert a bit from each byte in an 8-byte number to a single byte
我有一个64位无符号整数。我想检查每个字节的第6位,并返回一个表示第6位的字节。
显而易见的"暴力"解决方案是:
inline const unsigned char Get6thBits(unsigned long long num) {
unsigned char byte(0);
for (int i = 7; i >= 0; --i) {
byte <<= 1;
byte |= bool((0x20 << 8 * i) & num);
}
return byte;
}
我可以将循环展开为一堆串联的|
语句,以避免int
分配,但这仍然很难看。
有没有更快、更聪明的方法?也许可以使用位掩码来获得第6位0x2020202020202020
,然后以某种方式将其转换为字节?
如果_pext_u64
是可能的(这将在Haswell和更新版本上工作,但在Ryzen上非常慢),您可以写下:
int extracted = _pext_u64(num, 0x2020202020202020);
这是一种真正的字面实现方式。pext
取一个值(第一个参数)和一个掩码(第二个参数),在掩码有一个设置位的每个位置,它从值中取相应的位,所有位都被连接起来。
_mm_movemask_epi8
的可用性更广,您可以这样使用它:
__m128i n = _mm_set_epi64x(0, num);
int extracted = _mm_movemask_epi8(_mm_slli_epi64(n, 2));
CCD_ 7取其输入向量中每个字节的高位并将它们连接起来。我们想要的比特不是每个字节的高位,所以我用psllq
将它们向上移动两个位置(当然你可以直接移动num
)。CCD_ 10只是将CCD_。
别忘了#include <intrin.h>
,这些都没有经过测试。
Codegen似乎足够合理
一个更奇怪的选择是用乘法来收集比特:(仅经过轻微测试)
int extracted = (num & 0x2020202020202020) * 0x08102040810204 >> 56;
这里的想法是num & 0x2020202020202020
只有很少的比特集,所以我们可以安排一个从不携带我们需要的比特(或者根本不携带)的乘积。乘法器是这样构造的:
a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000 +
0b0000000c0000000d0000000e0000000f0000000g0000000h00000000000000 +
00c0000000d0000000e0000000f0000000g0000000h000000000000000000000 etc..
然后,顶部字节将所有位"压缩"在一起。低位字节实际上也有类似的东西,但它们缺少必须来自"高位"的位(在乘法运算中,位只能向左移动)。
相关文章:
- 一位朋友将模板函数缩写为clang和gcc
- 在java中读取c++字节的位字段
- 斐波那契数列部分和的最后一位数字
- 将第 n 个斐波那契数的大斐波那契数的最后一位编程.C++
- 如何检查 int 中是否恰好设置了一位?
- 如何找到由公式计算的非常大的数字的最后一位数字?
- 我如何使用十一位数字
- 使用位操作将8字节数字中的每个字节中的一位转换为单个字节
- 我在spoj-lastdig2中使用我的代码 - 重新访问的最后一位数字
- 查找非常大的 2^n 数字的最后一位数字
- 如何计算具有相同SHA-160和的另一位模式
- C++ 仅输出一个小数点后一位
- 如何将用户输入的最小值限制为流大小减去一位
- 如何为一次只写一位的程序编写测试程序
- 减去2个数字的每一位
- 找到一个提升到一定幂的数字的最后一位
- 如何在c++中交换数字的第一位和最后一位
- 如果机器每字节> 8 位,int8_t是什么?
- 根据c++社区中一位知识渊博的作者的说法,下面显示的代码应该无法编译.他错了吗?
- 将浮点数四舍五入到小数点后一位,然后转换为字符串