c – 具有任意边界的快速,无偏,整数伪随机生成器
作者:互联网
对于monte carlo集成过程,我需要从中抽取大量随机样本
具有N个桶的直方图,其中N是任意的(即不是2的幂)但是
在计算过程中根本不会改变.
很多,我的意思是大约10 ^ 10,10亿,几乎任何东西
面对绝对的数字,一种冗长的预计算可能是值得的
样本).
我有一个非常快速的统一伪随机数发生器
通常产生无符号的64位整数(讨论中的所有内容)
以下是未签名的).
拉取样本的天真方式:histogram [prng()%histogram.size()]
天真的方式非常慢:模运算使用整数除法(IDIV)
这是非常昂贵的编译器,不知道histogram.size()的值
在编译时,不能达到其通常的魔力(即http://www.azillionmonkeys.com/qed/adiv.html)
事实上,我的大部分计算时间都花在提取该模型上.
稍微不那么天真的方式:我使用有能力的libdivide(http://libdivide.com/)
通过在编译时未知的常数来划分非常快速的“除以”.
这给了我一个非常好的胜利(25%左右),但我有一种唠叨的感觉,我能做到
更好,这就是原因:
>第一直觉:libdivide计算一个分裂.我需要的是模数,并达到目的
我必须做一个额外的mult和sub:mod = dividend – divisor *(uint64_t)(dividend / divisor).我怀疑使用libdivide-type可能会有一个小胜利
直接生成模数的技术.
>第二种直觉:我实际上对模数本身不感兴趣.我真正想要的是
有效地产生均匀分布的整数值,保证严格小于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 [
(PS:我知道如果N很小,我不需要输入所有64位
PRNG.事实上,我已经这样做了.但就像我说的那样,即使是那种优化
与必须计算模数的大量减肥相比,这是一个小小的胜利.
编辑:prng()%N确实不是完全均匀分布的.但是对于N足够大,我认为这不是问题(或者是它?)
编辑2:prng()%N确实可能分布很差.我从来没有意识到它会变得多么糟糕.哎哟.我发现了一篇很好的文章:http://ericlippert.com/2013/12/16/how-much-bias-is-introduced-by-the-remainder-technique
解决方法:
如果您可以快速访问所需的指令,则可以通过N将64位乘以prng()并返回128位结果的高64位.这有点像将[0,1]中的统一实数乘以N并截断,模数版本的偏差(即实际上可忽略不计;这个答案的32位版本会有小但可能明显的偏差).
探索的另一种可能性是在单个位上操作的无分支模数算法上使用字并行,以批量获得随机数.
标签:random-sample,c,performance,algorithm,random 来源: https://codeday.me/bug/20190722/1506225.html