繁体   English   中英

设置/清除位:bitshift或bitmask lookup?

[英]Setting/clearing bits: bitshift or bitmask lookup?

我正在研究一个基于位板的国际象棋引擎,其中一个大概执行的操作是在无符号的64位整数中设置/清除位。 由于我不熟悉哪些代码在某些处理器上“运行得更快”,所以我无法完全理解这一点。

设置和清除位是一个非常简单的操作,但我应该使用(用于设置):

uint64_t bitboard |= 1ULL << index;

要么:

uint64_t bitboard |= BITMASK[index];

其中BITMASK[]是一些预先计算的整数数组,其中只有一位(在index )被设置。

乍一看,位移似乎是明显更快的选择,因为位移总是比内存查找更快。

但是在国际象棋引擎的上下文中,可能会大量执行此操作,将查找表存储在处理器的缓存中是有意义的,这可能会使查找表的使用速度更快。 或者是吗?

而且,它甚至有所作为吗?

也许是一个愚蠢的考虑因素,但要知道它并没有坏处。

与表查找相比,shift方法应该更快,因为它避免了额外的内存引用。 但出于教育目的,基准测试会很有趣。

我很快就掀起了这个(非常原始,赦免)的功能:

#include <iostream>
#include <random> // std::mt19937()

typedef unsigned long long uint64;

uint64 SET_BITMASK[64];

void init_bitmask()
{
    for(int i = 0; i < 64; i++) SET_BITMASK[i] = 1ULL << i;
}

int main()
{
    std::mt19937 gen_rand(42);
    uint64 bb = 0ULL;
    double avg1, avg2;

    init_bitmask();

    for(unsigned int i = 0; i < 10; i++)
    {
        std::clock_t begin = std::clock();

        for(unsigned int j = 0; j < 99999999; j++)
        {
            bb |= 1ULL << (gen_rand() % 64);
        }

        std::clock_t end = std::clock();

        std::cout << "For bitshifts, it took: " << (double) (end - begin) / CLOCKS_PER_SEC << "s." << std::endl;
        avg1 += (double) (end - begin) / CLOCKS_PER_SEC;

        bb = 0ULL;

        begin = std::clock();

        for(unsigned int j = 0; j < 99999999; j++)
        {
            bb |= SET_BITMASK[gen_rand() % 64];
        }

        end = std::clock();

        std::cout << "For lookups, it took: " << (double) (end - begin) / CLOCKS_PER_SEC << "s." << std::endl << std::endl;
        avg2 += (double) (end - begin) / CLOCKS_PER_SEC;
    }

    std::cout << std::endl << std::endl << std::endl;

    std::cout << "For bitshifts, the average is: " << avg1 / 10 << "s." << std::endl;
    std::cout << "For lookups, the average is: " << avg2 / 10 << "s." << std::endl;
    std::cout << "Lookups are faster by " << (((avg1 / 10) - (avg2 / 10)) / (avg2 / 10))*100 << "%." << std::endl;
}

每次迭代十一亿多位套的平均值1.61603s为bitshifts和1.57592s进行查找一致(甚至是不同的种子值)。

令人惊讶的查找表似乎始终快了大约2.5% (在这个特定的用例中)。

注意:我使用随机数来防止任何不一致,如下所示。

如果我使用i % 64来移位/索引,则位移的速度提高约6%

如果我使用常数来移位/索引,输出变化大约8%,介于-4%和4%之间,这让我觉得一些有趣的猜测业务正在发挥作用。 要么是,要么平均为0%;)

我无法得出结论,因为这肯定不是一个真实的场景,因为即使在国际象棋引擎中,这些设置的比特案例也不会快速连续地相互跟随。 我只能说,差异可能微不足道。 我还可以补充一点,查找表是不一致的,因为您是否已经缓存了表格。 我个人会在我的引擎中使用bithifts。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM