C++ 迭代位的最快方法
我已经在一个国际象棋引擎上工作了一段时间,它相当强大(大约2700 CCRL),我想知道以下事情: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 /**
大多数顶级象棋引擎都使用比特板。它们基本上只是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);
...
}
然而,第二个结果是较慢(出于某种原因)
我的问题是:
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