我需要在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万个整数。
但是有一个大问题。当我分析使用按位和&采样的整数时。方法,它们不会在[LB,UB]
区间内均匀分布。整数确实来自[LB,UB]
,但仅>>来自该范围内的偶数整数。例如,这里是使用按位&和从[20,50]采样的5000个整数的直方图。方法:
相比之下,这是使用mod运算符方法时类似的直方图,当然可以正常工作:
我的bitwise&有什么问题?方法?有没有办法修改它,以便在定义的时间间隔内对偶数和奇数进行采样?
答案 0 :(得分:2)
如果范围差异(UB-LB
)为2 n -1,则效果很好,但如果例如2 n 则无法正常工作。
答案 1 :(得分:2)
按位&
运算符查看其操作数的每对相应位,仅使用这两位执行and
,并将该结果放入结果的相应位。
因此,如果UB-LB
的最后一位为0,则结果的最后一位为0
。也就是说,如果UB-LB
是偶数,那么每个输出都是偶数。
&
不适合此目的,除非UB-LB+1
是2的幂。如果你想找到一个模数,那么就没有一般的捷径:编译器已经实现{{1}它知道的最快的方式。
请注意,我没有说一般快捷方式。对于编译时已知的%
的特定值,可以有更快的方法。如果你能以某种方式安排UB-LB
和UB
具有编译器在编译时可以计算的值,那么当你编写LB
时它将使用它们。
顺便说一句,使用%
实际上并不会在整个范围内产生均匀分布的整数,除非范围的大小是2的幂。否则必须有一些偏向某些值的偏差,因为%
函数的范围无法在所需范围内平均分配。可能是偏差太小而不能特别影响您的模拟,但是糟糕的随机数生成器在过去已经破坏了随机模拟,并且会再次这样做。
如果您希望在任意范围内均匀随机数分布,请使用C ++ 11中的int64()
或Boost中相同名称的类。
答案 2 :(得分:1)
只有当间隔的大小是2的幂时,两者才是等价的。通常y%x和y&(x-1)不相同。
例如,x%5产生的数字从0到4(或者为-4,对于负x),但x& 4产生0或4,从不产生1,2或3,因为按位运算符的工作方式如何...