创建新蒙版

问题描述 投票:0回答:1

我正在寻找一种最佳方法,该方法将基于 ulong 列表,查看 4 位对,如果这些位中的任何一个设置为 1,则应该将新 ulong 值中的第一位设置为 1否则为 0。

例如

列表 qwords = new List() {0x1, 0x1, 0x1} ulong myMask = 0;

现在依次检查每个 qword 的所有 4 位对,我们应该得到以下值。

新值:0001 0000 0000 0000 0001 0000 0000 0000 0001

我的掩码 = 4295032833(0x100010001)

列表中给出的示例只是为了更容易理解代码逻辑是如何工作的。 谁能帮助我如何最佳地解决这个问题?

c# algorithm bit-manipulation bit
1个回答
0
投票

据我了解这个问题,我们计算每个半字节是否设置了任何位,然后我们“压缩”它以获得一个掩码,指示哪个半字节至少有一个设置位。

第一步很简单:

for (int i = 0; i < qwords.Length; i++)
{
    ulong bits = qwords[i];
    bits |= bits >> 1;
    bits |= bits >> 2;
    qwords[i] = bits;
}

我正在此处修改原始列表,但当然欢迎您将中间结果放在其他地方。

然后,如果我们被允许使用 System.Runtime.Intrinsics.X86 并且支持 BMI2,我们可以像这样进行“压缩”(对于 4 个 qword 的列表):

ulong m = 0x1111111111111111;
ulong myMask = Bmi2.X64.ParallelBitExtract(qwords[0], m) |
    (Bmi2.X64.ParallelBitExtract(qwords[1], m) << 16) |
    (Bmi2.X64.ParallelBitExtract(qwords[2], m) << 32) |
    (Bmi2.X64.ParallelBitExtract(qwords[3], m) << 48);

否则,使用方法

compress
(下文进一步介绍)我们可以做到这一点:

ulong myMask = compress(qwords[0]) |
    (compress(qwords[1]) << 16) |
    (compress(qwords[2]) << 32) |
    (compress(qwords[3]) << 48);

我们可以像这样

compress

ulong compress(ulong x)
{
    x = (x & 0x0101010101010101) | ((x & 0x1010101010101010) >> 3);
    x = (x & 0x0003000300030003) | ((x & 0x0300030003000300) >> 6);
    x = (x & 0x0000000F0000000F) | ((x & 0x000F0000000F0000) >> 12);
    x = (x & 0x00000000000000FF) | ((x & 0x000000FF00000000) >> 24);
    return x;
}

对于最多 4 个 qword 的列表:

ulong myMask = 0;
for (int i = 0; i < qwords.Length; i++)
{
    ulong bits = qwords[i];
    bits |= bits >> 1;
    bits |= bits >> 2;
    myMask |= compress(bits) << (i * 16);
}
© www.soinside.com 2019 - 2024. All rights reserved.