C++ 迭代位的最快方法

C++ 迭代位的最快方法,c++,binary,bit,chess,bitboard,C++,Binary,Bit,Chess,Bitboard,我已经在一个国际象棋引擎上工作了一段时间,它相当强大(大约2700 CCRL),我想知道以下事情: 大多数顶级象棋引擎都使用比特板。它们基本上只是64位数字,表示一些二进制数据,比如是否有一个正方形被占用。在很多应用程序中,bitboard很方便,但在很多情况下,我需要迭代所有位,并使用设置位的索引 我预先定义的一些功能: typedef uint64_t U64; typedef int8_t Square; //its signed for different reasons /**

我已经在一个国际象棋引擎上工作了一段时间,它相当强大(大约2700 CCRL),我想知道以下事情:


大多数顶级象棋引擎都使用比特板。它们基本上只是64位数字,表示一些二进制数据,比如是否有一个正方形被占用。在很多应用程序中,bitboard很方便,但在很多情况下,我需要迭代所有位,并使用设置位的索引

我预先定义的一些功能:

typedef uint64_t U64;
typedef int8_t Square;  //its signed for different reasons

/**
 * returns the index of the LSB
 * @param bb
 * @return
 */
inline Square bitscanForward(U64 bb) {
//    assert(bb != 0);
    return __builtin_ctzll(bb);
}


/**
 * resets the lsb in the given number and returns the result.
 * @param number
 * @return
 */
inline U64 lsbReset(U64 number) {
    return number & (number - 1);;
}
使用这两种方法,我通常会像这样迭代比特板:

U64 bb = ....

while(bb){
   Square s = bitscanForward(bb);
   ...
   bb = lsbReset(bb);
}
另一种解决办法是:

for(;bb!=0;bb=lsbReset(bb)){
   Square s = bitscanForward(bb);
   ...
}
然而,第二个结果是较慢(出于某种原因)

我的问题是:

  • 为什么第二种方法较慢
  • 还有更快的方法吗?特别是通过调整一些计算来减少时钟周期
  • 编辑1 如我所愿,我发布了我的测试代码。 事实上,我发现了一个小错误,他们两个以相同的速度运行。 但问题在于是否有更好的实现

      U64 k = randU64();
        printBitmap(k);
        
        startMeasure();
        int sum = 0;
        for(int i = 0; i < 1e8; i++){
            U64 copy = k;
            while(copy){
                Square s = bitscanForward(copy);
                sum += s;
                
                copy = lsbReset(copy);
            }
        }
        std::cout << stopMeasure() << "ms sum="<<sum << std::endl;
        
        startMeasure();
         sum = 0;
        for(int i = 0; i < 1e8; i++){
            U64 copy = k;
            for(;copy!=0;copy=lsbReset(copy)){
                Square s = bitscanForward(copy);
                sum += s;
        
            }
        }
        std::cout << stopMeasure() << "ms sum="<<sum << std::endl;
    

    为什么不直接将电路板存储在
    向量
    位集中
    ?它是空间优化,将采取相同的空间作为您的比特板,而且它将很容易迭代也。位集比数组更快,而且内存效率也更高。对于位集,只有您需要通过
    [i][j]
    访问,而不是通过
    [i*8+j]
    访问。向我们展示您是如何测量的,您用于构建应用程序的编译器选项,如优化级别,等等。@brc dd我相当肯定这不是一个节省空间的方法,特别是因为一个布尔值将是8位。@PaulMcKenzie是的,我可以做到。1.sec@brc-dd这是一个不错的建议,但迭代不会是稀疏的,每一位都会花费一个几乎不可预测的分支。它对各种非琐碎的位板操作(例如转置或
    o^(o-2r)
    技巧)也不是很友好。为什么不直接将板存储在
    vector
    位集中呢?它是空间优化,将采取相同的空间作为您的比特板,而且它将很容易迭代也。位集比数组更快,而且内存效率也更高。对于位集,只有您需要通过
    [i][j]
    访问,而不是通过
    [i*8+j]
    访问。向我们展示您是如何测量的,您用于构建应用程序的编译器选项,如优化级别,等等。@brc dd我相当肯定这不是一个节省空间的方法,特别是因为一个布尔值将是8位。@PaulMcKenzie是的,我可以做到。1.sec@brc-dd这是一个不错的建议,但迭代不会是稀疏的,每一位都会花费一个几乎不可预测的分支。它对各种非平凡的位板操作(例如转置或
    o^(o-2r)
    技巧)也不是很友好。
    10101001
    01011111
    00011111
    00000111
    01010001
    00000011
    00110001
    10010100
    
    1748ms sum=-1174182400
    1757ms sum=-1174182400