通过Cactus Kev's Poker Hand Evaluator阅读,我注意到以下陈述:
起初,我认为在将它传递给评估者之前,我总是可以先简单地对手进行排序;但排序需要时间,我不想浪费任何CPU周期整理手。我需要一种不关心五张牌的顺序的方法。
...
经过深思熟虑,我有一个头脑风暴来使用素数。我会给十三个卡片等级中的每一个分配一个素数值......这个系统的优点在于,如果你将每张卡片的等级的主要值乘以你手中,你将获得一个独特的产品,无论订单如何五张牌。
...
由于乘法是计算机可以进行的最快计算之一,如果我们在评估之前被迫对每只手进行排序,我们已经减少了几百毫秒。
我很难相信这一点。
Cactus Kev将每张卡片表示为4字节整数,并通过调用eval_5cards( int c1, int c2, int c3, int c4, int c5 )
来评估指针。我们可以将卡表示为一个字节,将扑克手表示为5字节数组。对这个5字节数组进行排序以获得一个独特的手必须非常快。它比他的方法快吗?
如果我们保留他的表示(卡片为4字节整数)怎么办?可以对5个整数的数组进行排序比乘以它们更快吗?如果没有,可以采用什么样的低级优化来更快地对少量元素进行排序?
谢谢!
每个人都很好的答案;我正在对排序与乘法的性能进行基准测试,以获得一些硬性能统计数据。
答案 0 :(得分:6)
没有测试,我对他的论点表示同情。与排序相比,您可以在4次乘法中进行,n log n
。具体而言,最佳sorting network需要进行9次比较。然后,求值程序必须至少查看已排序数组的每个元素,这是另外5个操作。
答案 1 :(得分:6)
当然,它很大程度上取决于您的计算机的CPU,但典型的Intel CPU(例如Core 2 Duo)可以在3个CPU时钟周期内乘以两个32位数。对于要击败它的排序算法,算法需要比3 * 4 = 12个CPU周期更快,这是一个非常严格的约束。没有一种标准排序算法可以在少于12个周期内完成。单独比较两个数字将占用一个CPU周期,结果上的条件分支也将占用一个CPU周期,无论你做什么,至少需要一个CPU周期(交换两个卡实际上至少需要4个CPU周期)。所以倍增胜利。
当然,这并不考虑延迟来从第一级或第二级缓存甚至内存中获取卡值;但是,这种延迟适用于案例,乘法和排序。
答案 2 :(得分:5)
排序本质上并不比数字乘法更难。从理论上讲,它们大致相同,而且你还需要一种复杂的乘法算法来使大型乘法与大型竞争相提并论。此外,当提出的乘法算法可行时,您也可以使用桶式排序,它渐近更快。
然而,扑克牌不是渐近问题。它只有5张牌,他只关心卡的13个数值中的一个。即使乘法原则上复杂,实际上它也是用微码实现的,并且速度非常快。他正在做什么。
现在,如果你对理论问题感兴趣,还有一个使用加法而不是乘法的解决方案。任何一个值只能有4张卡,所以您也可以分配值1,5,25,...,5 ^ 12并添加它们。它仍适用于32位算术。还有其他基于加法的解决方案与其他数学属性。但它确实无关紧要,因为微编码算法比计算机正在做的任何事情都要快得多。
答案 3 :(得分:2)
可以使用优化的决策树对5个元素进行排序,这比使用通用排序算法要快得多。
然而,事实仍然是排序意味着许多分支(与之后必要的比较一样)。对于现代流水线CPU架构而言,分支机构确实不好,尤其是具有相似可能性的分支(从而破坏分支预测逻辑)。这远远超过乘法与比较的理论成本,使得乘法更快。
但是如果您可以构建自定义硬件来进行排序,可能会更快地结束。
答案 4 :(得分:1)
这不应该真正相关,但他是正确的。排序比乘法需要更长的时间。
真正的问题是他对所得到的素数做了什么,以及它是如何有用的(因为考虑到它我会比分类花费更长的时间。
答案 5 :(得分:1)
很难想象任何排序操作可能比乘以同一组数字更快。在处理器级别,乘法只是load, load, multiply, load, multiply, ...
,可能会对累加器进行一些操作。它是线性的,易于流水线化,不与相关的分支误预测成本进行比较。它应该平均每个值大约2个指令乘以。除非乘法指令非常缓慢,否则很难想象更快的排序。
答案 6 :(得分:1)
值得一提的是,即使你的CPU的乘法指令死得很慢(或者不存在......),你也可以使用查找表来进一步加快速度。
答案 7 :(得分:1)
经过深思熟虑,我有一个头脑风暴来使用素数。我会给十三个卡片等级中的每一个分配一个素数值......这个系统的优点在于,如果你将每张卡片的等级的主要值乘以你手中,你将获得一个独特的产品,无论订单如何五张牌。
这是一个非位置数字系统的例子。
我找不到理论的链接。我研究了它作为应用代数的一部分,在欧拉的总体和加密周围。 (我用术语研究了所有这些术语,这可能是错的。)
如果我们保留他的表示(卡片为4字节整数)怎么办?可以对5个整数的数组进行排序比乘以它们更快吗?
RAM是一种外部资源,与CPU相比通常较慢。由于交换操作,排序5个整数总是必须转到RAM。在这里添加排序函数本身的开销,并且乘法停止查看所有坏的。
我认为在现代CPU上整数乘法几乎总是比排序快,因为几个乘法可以在不同的ALU上同时执行,而只有一个总线将CPU连接到RAM。
如果没有,可以采取哪种低级优化来更快地对少量元素进行排序?
使用bubble sort可以非常快速地对5个整数进行排序:qsort将使用更多内存(用于递归),而优化良好的冒泡排序可以完全从d-cache中完成。
答案 8 :(得分:0)
正如其他人所指出的,单独排序并不比5个值的乘法快。然而,这忽略了他的其余解决方案。在蔑视5元素排序之后,他继续对4888个值进行二元搜索 - 至少进行12次比较,超过了所需的数量!
请注意,我并不是说有一个更好的解决方案涉及排序 - 我个人没有给予足够的思考 - 仅仅排序只是问题的一部分。
他也没有必要使用素数。如果他只是用4位编码每张卡的值,他需要20位代表一只手,给出0到2 ^ 20 = 1048576的范围,大约是使用素数产生的范围的1/100,并且足够小(尽管仍然存在缓存一致性问题)以生成查找表。
当然,一个更有趣的变体是拿7张牌,比如德州扑克等游戏中找到的牌,找到可以用它们制作的最好的5张牌。
答案 9 :(得分:0)
乘法更快。
任何给定数组的乘法总是比排序数组快,假设乘法产生有意义的结果,并且查找表无关紧要,因为代码旨在评估扑克牌,所以你需要做一个无论如何都要在有序集上查找。
答案 10 :(得分:0)