【发布时间】:2016-03-08 22:26:56
【问题描述】:
我对“扩展位”的快速方法感兴趣,可以定义如下:
- 令B为n位的二进制数,即B\in {0,1}^n时间>
- 令P为B中所有1/true位的位置,即
1 << p[i] & B == 1,且|P|=k - 对于另一个给定数,A \in {0,1}^k,令 Ap 为 Ap 的位扩展形式em>A 给定 B,这样
Ap[j] == A[j] << p[j]。 - “位扩展”的结果是Ap。
几个例子:
- 给定B:0010 1110,A:0110,然后Ap 应该是 0000 1100
- 给定 B:1001 1001,A:1101,那么Ap应该是1001 0001
以下是一种简单的算法,但我不禁感到有一种更快/更简单的方法可以做到这一点。
unsigned int expand_bits(unsigned int A, unsigned int B, int n) {
int k = popcount(B); // cuda function, but there are good methods for this
unsigned int Ap = 0;
int j = k-1;
// Starting at the most significant bit,
for (int i = n - 1; i >= 0; --i) {
Ap <<= 1;
// if B is 1, add the value at A[j] to Ap, decrement j.
if (B & (1 << i)) {
Ap += (A >> j--) & 1;
}
}
return Ap;
}
【问题讨论】:
-
这看起来像 x86 指令集的 AVX 扩展中的
PDEP指令的功能(它也作为内在函数公开)。我不知道在 NVIDIA GPU 上具有类似功能的 GPU 指令,并且没有 CUDA 内在函数。您是否需要完全通用模拟此功能,或者您实际上是在查看特定的、定义更狭义的此类比特沉积的实例? -
你能澄清一下规范吗?据我所知,
A是要存放其位的操作数,B是控制每个存放位的目标位的掩码。n的作用到底是什么?由于B可能有一些稀疏性,似乎最好从最不重要的一端开始迭代B中的1 位。 -
@njuffa 我刚刚查看了
PDEP和PEXT指令,它看起来更接近PEXT指令。关于您的其他问题,我需要完整的此功能。B的值范围从0到~0,但我只关心低于给定值的k的值。n的值只是数字的位数——uint32_t为 32,short为 16。 -
你在问题中给出的例子对应
PDEP;在发布答案之前,我还在下面的代码中运行了这两个示例:pdep (0x6, 0x2e) = 0c; pdep (0xd, 0x99) = 91。由于n似乎只是操作数中的位数,因此不需要它。如果您需要各种操作数类型的版本,您可以使用模板创建重载版本,因为 CUDA 是 C++ 的子集。 -
@njuffa 你是对的。感谢您指出这一点。
标签: algorithm cuda bit-manipulation