快速排名/排名组合(64位)

时间:2016-07-26 12:45:38

标签: c++ 64-bit combinations rank bitset

有这篇伟大的帖子 https://stackoverflow.com/a/3143594/6589735 概述排名/排名组合的算法。 此外,在C ++中有一些具体的实现,例如这里https://people.sc.fsu.edu/~jburkardt/cpp_src/combo/combo.cpp

我需要在C ++中实现非常快的实现,它在x64 Haswell CPU上对unsigned long long编码的排名/解包组合进行排序/取消。

我的尝试非常需要改进。

unsigned long long rank(unsigned long long comb, int card)
{
    unsigned long long rank = 0;

    for (int i = 1; i <= card; i++)
    {
        unsigned long index;
        _BitScanForward64(&index, comb);
        rank += binCoef[index][i];  // the binCoef table is precomputed
        comb &= (comb - 1);
    }

    return rank;
}

unsigned long long unrank(unsigned long long rank, int card)
{
    unsigned long long comb = 0;

    unsigned long long m = rank;
    for (int i = card - 1; i >= 0; i--)
    {
        int p = i;
        while (binCoef[p + 1][i + 1] <= m)
            p++;
        m -= binCoef[p][i + 1];
        comb |= (1 << p);
    }

    return comb;
}

1 个答案:

答案 0 :(得分:1)

我认为你已经很顺利了。您是否正在做一些与扑克相关的事情? (当我这样做时,我只是用Google搜索了无法解决的算法)。一些注意事项:

1)对于少量项目,二项式可以比内存访问更快地手动计算,但考虑到很长时间,这在你的情况下是不太可能的。

2)但是,根据编译器的智能,您可以通过计算precalc表的2D索引来保存内存访问:

binCoef[(index<<6) + i]; // instead of binCoef[index][i]

3)在计算过程中不确定binCoef在L1缓存中的适用程度,但是您可以使用标识C(n,k)== C(n,nk)保存一半的查找空间一个额外的条件。也许值得测试?

4)在unrank中,我认为内部while循环是最慢的部分。有两个明显的优化:要么实现二进制搜索来定位p,要么......

5)如果你正在处理card的小值,你甚至可以考虑全面的查找解决方案来解决:有C(52,5)= 260万扑克牌,这只是少数几个查找MB。

6)同样,您可能会看到是否可以使用map<int, long long> rank来完全替换排名算法。二叉树是用于查找的O(log N),并且哈希映射可能具有更好的性能。只是预先确认:

map<long long, int> rank5;
for(int i=0; i<N; i++) rank5[unrank(i, 5)] = i; //ranks of 5 card hands

如果您需要较大的card值,那么查找方法将无法正常工作,我认为您几乎完全坚持使用二进制搜索优化。祝你好运!