通过很多,我的意思是大约10^10,100亿,因此面对如此庞大的样本数量,任何一种漫长的预处理都可能是值得的。
我可以使用非常快速的均匀伪随机数生成器,通常会产生64位无符号整数(以下讨论中的所有整数都是无符号的)。
拉取样本的朴素方法:histogram [prng()%histogram.size()]
这种朴素方法非常慢:模运算使用整数除法(IDIV),非常昂贵,编译器不知道histogram.size()
的值在编译时,不能像平常那样进行优化(即http://www.azillionmonkeys.com/qed/adiv.html)。
稍微不那么天真的方法:我使用libdivide(http://libdivide.com/),它能够快速执行“除以编译时不知道的常量”。这给了我一个非常好的优势(约25%),但我有一种困扰的感觉,认为我可以做得更好,原因如下:
- 第一直觉:libdivide计算除法。我需要的是模数,为了到达目的地,我必须进行额外的乘法和减法:
mod = dividend - divisor*(uint64_t)(dividend/divisor)
。我怀疑可能有一个小胜利,在使用libdivide类型的技术直接生成模数方面。
- 第二直觉:我实际上并不关心模数本身。我真正想要的是有效地生成一个保证严格小于N的均匀分布的整数值。模数是实现这一目标的一种相当标准的方法,因为它具有两个属性:
A) 如果
prng()
满足要求,那么mod(prng(),N)
保证是均匀分布的B)
mod(prgn(),N)
保证属于[0,N [
但是取模运算除了满足上述两个限制条件外,还有更多作用,事实上它可能做了太多工作。
我们需要的只是一个函数,任何函数都符合A)和B)的约束条件,并且具有快速性。
所以,长话短说,这里有两个问题:
是否存在与libdivide等价的计算整数取模的方法?
是否存在整数X和N的函数F(X,N),它遵循以下两个约束条件:
- 如果X是均匀分布的随机变量,则F(X,N)也是均匀分布的
- F(X,N)保证在[0,N [内
编辑:
prng() % N
确实不是完全均匀分布的。但对于足够大的N,我认为这不是什么大问题(或者是吗?)编辑2:
prng() % N
可能非常差地分布。我从未意识到它会有多糟糕。哎呀。我在这里找到了一篇好文章:http://ericlippert.com/2013/12/16/how-much-bias-is-introduced-by-the-remainder-technique
N
能够整除M
时,才能保证prng()
返回的数字在[0, M[
范围内进行取模操作后得到的结果mod(prng(), N)
均匀分布。请注意,prng()
返回的是均匀分布的随机数。 - huonstd::uniform_int_distribution
吗? - Jarod42N
?假设您在“现代”x86上,N > (256kB/8B) = 32k将导致L2缓存溢出,这必定会成为主要的性能影响。 - Oliver Charlesworthhistogram[ (int)(prng() * (HISTOGRAM_SIZE / (PRNG_MAX + 1.0))) ]
。每个直方图预先计算常量一次。这将编译为一个浮点乘法和一个整数转换。使用MMX或GPU实现可以同时处理多个。但是,如果您使用随机直方图访问来清除缓存,我同意@OliCharlesworth的看法,这是一个巨大的代价。 - Gene