【问题标题】:Fast ranking/unranking of combinations (64bit)组合的快速排名/取消排名(64 位)
【发布时间】:2016-07-26 12:45:38
【问题描述】:

有这个很棒的帖子 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;
}

【问题讨论】:

  • 抱歉,您有什么好问题?
  • @MSalters:将语言更改为 C++
  • 因为无论如何你都在预计算,你可以预计算更多,例如位掩码的每个可能字节的总和。然后不要循环遍历这些位,而是使用pdep 屏蔽它们。
  • @FirstStep:我给出了一个算法的 C++ 实现。问题是:如何提高速度(执行时间)?
  • 那你没找对地方。转至CodeReview

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


【解决方案1】:

我认为你已经做得很好了。你在做一些与扑克有关的事情吗? (我只是在这样做时搜索了未排序算法)。一些注意事项:

1) 对于少量项目,手动计算二项式可能比内存访问更快,但考虑到 long long,这在您的情况下极不可能。

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

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

3) 不确定binCoef 在计算期间在 L1 缓存中的适合程度,但您可以节省一半的查找空间,标识为 C(n, k) == C(n, nk),成本为 1附加条件。也许值得测试?

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

5) 如果您正在处理 card 的小值,您甚至可以考虑使用完整的查找解决方案来取消排名:有 C(52, 5) = 260 万手牌,这只有几 MB查找。

6) 同样,您可能会看到map&lt;int, long long&gt; 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 值,那么查找方法将不起作用,我认为您几乎无法使用二分搜索优化。祝你好运!

【讨论】:

    猜你喜欢
    • 2013-07-15
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2020-12-05
    • 2017-08-08
    • 2021-06-06
    • 2010-10-04
    • 1970-01-01
    相关资源
    最近更新 更多