2013-05-14 97 views
2

对于32位整数,将其分成32个连续整数的整数,这样每个整数的整数连续的箱子。第一个bin包含0,第二个0..1等等直到0..2^31-1。将32位整数映射为32个bin,每个bin具有1,2,4..2^31个连续整数

最快的算法我能想出,给定一个32位的整数i,是对一个I7 5个周期(位扫描3个循环):

// bin is the number of leading zeroes, and then we clear the msb to get item 
bin_index = bsr(i) 
item = i^(1 << bin_index) 

或等同(以及它存储项0 ..2 ^(32-1)在0仓和仓31 0,但是这并不重要):

// bin is the number of trailing zeroes, and then we shift down by that many bits + 1 
bin_index = bsf(i) 
item = i >> (bin_index + 1) 

在每种情况下的bin索引被编码为主导数量/尾随零个比特,用1将它们与项目编号分开。您可以对前导或尾随进行相同的处理,并使用零来分隔它们。两者都不适用于i = 0,但这并不重要。

只要连续两个整数在每个连续的bin中结束并且整个bin中的整数总和为2^32-1,整数和bin/items之间的映射就可以是完全任意的。你能想到一个更有效的算法来在i7上分割32个整数吗?请记住,i7是超标量的,因此任何不依赖于彼此的操作都可以并行执行,直到每种指令类型的吞吐量。

+0

既然你提到i7,你可以尝试将整数转换为浮点数并提取指数以得到一个有偏见的bin_index。零需要特别关注。 – 2013-05-14 04:14:43

+0

看起来它不是一个胜利,http://www.agner.org/optimize/instruction_tables.pdf把操作放在一个i7上3 + 2个周期(不确定这里的+2是什么意思,但它与3是无关的足以杀死任何可能的收益 – Eloff 2013-05-14 11:33:06

+0

我更喜欢思考SSE单元并且至少并行执行4个操作 – 2013-05-14 13:40:08

回答

1

通过在计数零之前尝试对数据进行排序,可以改进算法。

例如,首先将其与2^31进行比较,如果其较大者将其放入该垃圾箱,则继续计算尾部零。有了这个,你现在有一半的数据集放入它的bin在2条指令中......可能是两个周期。另一半需要更长的时间,但最终的结果将是一个改进。如果想到的话,你可能会进一步优化这条线。

我想这也将取决于分支预测的效率。

+0

对于一个有序数组(可能是2),期望的速度是每个数字4个周期,但是我怀疑排序可以在每个元素的1-3个周期内完成,以达到平衡点 – 2013-05-14 06:24:57

+0

这是一个有趣的想法,但我无法对数据集进行排序,但我知道大部分时间值都小于2^31。但是在2条指令中的一半数据集和一半分支未命中的数据集绝对不是胜利((7 + 2 + brnach miss)/ 2> 4.5但是有一个变体解决方案将仓位0和1结合在一起(其他仓库保持不变)。然后我会在2条指令中使用3/4的数据集 - 一个可预测的分支t变成(7 + 2 +分支未命中)/ 4> 2.25。如果我们在一个随机pdf上在线找到的i7上的分支丢失取15个周期的值,它将是(7 + 2 + 15)/ 4 = 6。仍然是一个损失:( – Eloff 2013-05-14 11:19:31