【发布时间】:2013-09-11 13:39:51
【问题描述】:
我需要在 C++ 中的区间 [LB,UB] 上从整数的均匀分布中随机抽样。为此,我从一个“好”的 RN 生成器(来自 Numerical Recipes 3rd ed.)开始,它均匀地随机采样 64 位整数;我们就叫它int64()吧。
使用 mod 运算符,我可以通过以下方式从[LB,UB] 中的整数中采样:
LB+int64()%(UB-LB+1);
使用 mod 运算符的唯一问题是整数除法的速度很慢。于是,我又尝试了here建议的方法,即:
LB + (int64()&(UB-LB))
按位 & 方法的速度大约是 3 倍。这对我来说意义重大,因为我在 C++ 中的一个模拟需要随机采样大约 2000 万个整数。
但是有 1 个大问题。当我分析使用按位 & 方法采样的整数时,它们在区间 [LB,UB] 上看起来并不均匀分布。整数确实是从[LB,UB] 中采样的,但仅来自该范围内的偶数。例如,这是使用按位 & 方法从 [20,50] 采样的 5000 个整数的直方图:
相比之下,使用 mod 运算符方法时类似的直方图看起来像这样,当然效果很好:
我的按位 & 方法有什么问题?有没有办法修改它,以便在定义的间隔内对偶数和奇数进行采样?
【问题讨论】:
-
如果您不必做对,那么快速很容易。
<g>掩码给出有效分布的唯一情况是目标范围的大小是 2 的幂。 -
您是否考虑过在 (0,1) 范围内使用生成器,将其称为
u0_1(),然后进行乘法运算:LB+(int)(u0_1()*(UB-LB+1)?无论如何,基于模的方法通常会产生不一致的结果,应该避免。 -
@pjs 是的,这就是我今后将使用的。感谢您的建议。
-
@pjs 乘法应该是
LB+(int)(u0_1()*(UB-LB+1))还是LB+((int)u0_1())*(UB-LB+1)? -
@synaptik 你想要前者,后者总是会将 u0_1() 结果变为零,从而产生 LB。对不起,我的评论中缺少括号。
标签: c++ random bit-manipulation modulo integer-division