优化两个数组的按位与

Posted

技术标签:

【中文标题】优化两个数组的按位与【英文标题】:Optimization of bitwise AND of two arrays 【发布时间】:2015-03-23 20:02:36 【问题描述】:

似乎是一个简单的问题;我必须对两个数组进行按位与,如果任何两个位匹配,则返回 true,基本上:return ((dataArray & maskArray) != 0)

当然,这不是合法的 C++。目前的解决方案类似于:

uint32_t dataArray[BIG_NUM] //Pretend it's initialized
uint32_t maskArray[BIG_NUM] //Pretend it's initialized
bool returnVal = false;

for(int i = 0; i < BIG_NUM; i++)

    if((dataArray[i] & maskArray[i]) != 0)
    
        returnVal = true;
        break;
    

return returnVal;

虽然功能正常,但既不能并行也不能矢量化,因此很痛苦,10% 的 CPU 周期在此函数中被烧毁。关于如何清理它的任何想法?

编辑:意识到我不应该将底层成员 sizeof() 作为数组大小的一部分。

【问题讨论】:

你能缓存一个奇偶校验值或校验和作为大多数情况下的快速检查吗? [BIG_NUM * sizeof(uint32_t)]这里在做什么? @milleniumbug,显然没有完全注意我输入的内容;谢谢你的收获。 您使用的是 64 位计算机吗?如果是这样,并且如果可能,编译为使用 64 位整数。这将使您的吞吐量翻倍。 @MustafaOzturk,我希望我是,但也许在未来。我想我可以将类型转换为 size_t 数组,然后如果发生迁移,该函数将很好地重新编译。 【参考方案1】:

如果您通常返回false,以下可能会更快:

bool res = 0;
for (int i = 0; i < BIG_NUM; i++)

    res|= dataArray[i] & maskArray[i];      
   
return res;

甚至

bool res = 0;
for (int i = 0; i < BIG_NUM; i++)

    resArray[i] = dataArray[i] & maskArray[i];


for (int i = 0; i < BIG_NUM; i++)

    res |= resArray[i];

return res;

取决于你的编译器

【讨论】:

我试一试,甚至没有想过通过 OR 来累积结果,但这很有意义,也没有溢出的讨厌习惯。 【参考方案2】:

在这里,这应该有助于向量化,因为它只退出 8 的倍数,并且每八次计算只有一个分支预测(可能更快)。

for(int i = 0; i < BIG_NUM; i+=8)

    uint32_t branch_once_per_8_calcs=0;
    branch_once_per_8_calcs+=dataArray[i+0] & maskArray[i+0];
    branch_once_per_8_calcs+=dataArray[i+1] & maskArray[i+1];
    branch_once_per_8_calcs+=dataArray[i+2] & maskArray[i+2];
    branch_once_per_8_calcs+=dataArray[i+3] & maskArray[i+3];
    branch_once_per_8_calcs+=dataArray[i+4] & maskArray[i+4];
    branch_once_per_8_calcs+=dataArray[i+5] & maskArray[i+5];
    branch_once_per_8_calcs+=dataArray[i+6] & maskArray[i+6];
    branch_once_per_8_calcs+=dataArray[i+7] & maskArray[i+7];
    if(branch_once_per_8_calcs!= 0)
    
        returnVal = true;
        break;
    

您也可以将步长增加到 64 或 128,并在每一步结束时使用嵌套循环检查一次,这样可以更快。

for(int i = 0; i < BIG_NUM; i+=8)

    uint32_t branch_once_per_8_calcs=0;
    branch_once_per_8_calcs+=(dataArray[i+0] & maskArray[i+0]) | (dataArray[i+1] & maskArray[i+1]);
    branch_once_per_8_calcs+=(dataArray[i+2] & maskArray[i+2]) | (dataArray[i+3] & maskArray[i+3]);
    branch_once_per_8_calcs+=(dataArray[i+4] & maskArray[i+4]) | (dataArray[i+5] & maskArray[i+5]);
    branch_once_per_8_calcs+=(dataArray[i+6] & maskArray[i+6]) | (dataArray[i+7] & maskArray[i+7]);
    if(branch_once_per_8_calcs!= 0)
    
        returnVal = true;
        break;
    

使用较少的添加和分配。不要忘记检查可能导致误报的溢出。

【讨论】:

如果您将添加替换为 ors,您将不需要任何溢出检查。

以上是关于优化两个数组的按位与的主要内容,如果未能解决你的问题,请参考以下文章

位运算(按位与按位或异或)

c语言的按位运算符怎么操作!?

python中的按位与 +按位或+ 按位反+异或运算 +左移+右移

C语言里的按位异或运算符

按位与按位或按位异或等等(& | ^ ~ >> <<)

位运算符按位与按位或按位非左移右移原码反码补码