Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在与选择器位图中的1位重叠的位掩码中选择设置位的范围_C++_X86_Bit Manipulation_Bmi - Fatal编程技术网

C++ 在与选择器位图中的1位重叠的位掩码中选择设置位的范围

C++ 在与选择器位图中的1位重叠的位掩码中选择设置位的范围,c++,x86,bit-manipulation,bmi,C++,X86,Bit Manipulation,Bmi,鉴于: 一种位掩码A(例如,std::uint64\u t),它至少包含一组(1)位 一种选择器位掩码b,它是A的子集(即A&b==b),并且至少有一个位集 我想在a中选择与b中的位重叠的连续1位跨距: a = 0b1111001110001100; b = 0b0000001010001000; //c=0b0000001110001100 // XXXX YYY ZZ XXXX组在c中为0,因为b&XXXX为false。复制ZZ组是因为b设置了一个Z位。出于同样的原因,YY

鉴于:

  • 一种位掩码
    A
    (例如,
    std::uint64\u t
    ),它至少包含一组(
    1
    )位
  • 一种选择器位掩码
    b
    ,它是
    A
    的子集(即
    A&b==b
    ),并且至少有一个位集
我想在
a
中选择与
b
中的位重叠的连续1位跨距:

a = 0b1111001110001100;
b = 0b0000001010001000;
//c=0b0000001110001100
//    XXXX  YYY   ZZ
XXXX组在
c
中为0,因为
b&XXXX
为false。复制ZZ组是因为
b
设置了一个Z位。出于同样的原因,YYY组也设置在
c
请注意,
b
a
中的单个组中可以有多个设置位

因此,对于
a
中的
1
s的每个连续组,如果
b
1
位于任何位置,则设置
c
中的所有这些位。一个更复杂的例子:

std::uint64_t a = 0b1101110110101;
std::uint64_t b = 0b0001010010001;
// desired   c == 0b0001110110001
// contiguous groups   ^^^ ^^   ^  that overlap with a 1 in b

assert(a & b == b);           // b is a subset of a

std::uint64_t c = some_magic_operation(a, b);
assert(c == 0b0001110110001);
是否有任何位逻辑指令/内部指令(MMX、SSE、AVX、BMI1/BMI2)或位操作技巧,允许我从
a
b
有效地计算
c
?(即无环)


其他:

使用Denis回答中的提示,我只能想象基于循环的算法:

std::uint64_t a = 0b0110111001001101;
std::uint64_t b = 0b0100101000001101;
assert(a & b == b); // subset

std::cout << std::bitset< 16 >(a) << std::endl;
std::cout << std::bitset< 16 >(b) << std::endl;
std::uint64_t x = (a + b) & ~a;
std::uint64_t c = 0;
while ((x = (a & (x >> 1)))) { // length of longest 1-series times
    c |= x;
}
std::cout << std::bitset< 16 >(c) << std::endl;
std::uint64\u t a=0B0110111001101;
std::uint64_t b=0B010010100000101;
断言(a&b==b);//子集
std::cout(a)1)){//最长1系列时间的长度
c |=x;
}

std::cout(c)在
uint64\u t
的情况下,您可以执行以下操作:

让我们设置
a=0b11011101101
。至少有一个0位很重要。位掩码有4个单独的区域,用1位填充。如果执行
c=a+(a&b)
,则如果此区域中至少设置了一位
b
,则每个1填充区域将溢出。所以你可以检查一下,哪个区域被飞越了。例如,如果您希望在
a
的第2和第3区域中使用1位,则可以执行以下操作:

    assert(c & 0b00100010000);
    //              ^^^ ^^ this segments overflows

“a段”包括长度为1的段吗?@M.M是的,1段只是长度为1-s的非零序列。我花了大约10分钟来解码你的描述,所以我做了一个编辑以澄清未来的读者。我想你遗漏了英特尔的BMI1/BMI2扩展是偶然的,不是因为。您确实提到了AVX,它绝对不是基线:甚至在上也不受支持,只有i3和更高版本。谢谢,英特尔:(事实上,BMI指令本身都没有明显的用处。不过,可能将
pext
/
pdep
作为构建块。您是否绝对需要指定格式的输出?Denis的回答会丢失关于每个组有多大的信息,但每个匹配组的结果中都有一个1。@PeterCordes谢谢您的更正。我非常感谢。在我的实际情况中,MSB为零。很好。解释:
a&b==b
,因此该步骤是多余的。使用
&~a
掩蔽将删除
a
中选定组执行之外的所有位。