在日志空间中统一生成随机整数

时间:2016-06-16 03:38:12

标签: java math random distribution

我想生成在日志空间中均匀分布的随机整数。也就是说,值的对数将是均匀分布的。

正态均匀分布的无符号整数将有75%的幅度超过10亿,比100万以上99.98%,所以小值不足。来自日志空间的统一值在4-8范围内具有相同数量的值,例如256-512。

暂时忽略负值,我能想到的一种方式是:

Random r = new Random();
return (int)Math.pow(2, r.nextDouble() * 31);

这应该生成一个31位对数均匀分布。它不会很快,在那里进行pow()操作并引入浮点值来生成整数有点气味。此外,double遗失了Random.nextDouble()的很多范围,我不清楚这段代码是否甚至可以生成所有2 ^ 31-1正整数值。

欢迎更好的解决方案。

下面有两个类似的解决方案,它们都涉及用随机位填充整数,然后向右移位一个随机位数。类似的东西:

int number = rand.nextInt(Integer.MAX_VALUE) >> rand.nextInt(Integer.SIZE);

这有两种偏见:

逐步偏见

这会产生一种逐步的日志分布值,而不是平滑的值。特别是,在[0,31]中通过随机值右移意味着有31个同样可能的"尺寸"整数,并且该范围内的每个值都是同样可能的。由于范围N中有2 ^ N个值,因此一个范围内的值可能是下一个范围内的值的两倍 - 因此您可以获得范围之间的对数行为,但范围本身是平坦的。

我不知道摆脱这种偏见的简单方法。

最高位偏差

出现第二种形式的偏差是因为MSB并不总是1(例如,即使偏移量为10,也不需要产生31-10=21位值,还会产生额外的失真。范围重叠。对于移位量30,值1不仅存在(p(1)=。5),而且29的移位(p(1)= 0.25),28(p(1)这个效果取消了较小的值(即,如果你只看30和29的移位量,1似乎比2的可能性高3倍,而不是2倍的预测值,但是一旦你看到更多的值它就会收敛。但它并没有取消大值,这就是为什么你看到20:32207桶比@ sprinter的答案中的其他值小。

我认为这种形式的偏见可以很容易地通过强制顶部位为零来删除,所以类似于:

(r.nextInt(0x40000000) | 0x40000000) >> r.nextInt(31)

这有几个其他调整 - 兰特最多2 ^ 30,这更快(nextInt(int)代码中2的幂的特殊情况),因为我们从不想要第二个 - 来 - 无论如何MSB位设置(我们强制它为1)。这也消除了微观的额外偏差源,即无法生成Integer.MAX_VALUE,因此完全表示中缺少一个值。

它移位[0,31]位,所以你永远不会得零,如果你也想要零,改变它移位[0,32]位你会得到零的频率等于1(技术上不再进行日志分发,但在许多情况下很有用)。另一种方法是从最终值中减去一个以获得零(以永不获得Integer.MAX_VALUE为代价)。

1 个答案:

答案 0 :(得分:1)

提供的错误答案仅供参考。由于问题中给出的原因,这不符合OP的要求。

int number = rand.nextInt(Integer.MAX_VALUE) >> rand.nextInt(Integer.SIZE);

我对此的非正式测试似乎表明存在预期的偏差。我以这种方式生成了1M数字并且具有以下日志分布(忽略零)

0:46819
1:47045
2:40663
3:44001
4:45306
5:43802
6:46447
7:43355
8:47366
9:42747
10:46387
11:43899
12:45179
13:45496
14:44431
15:46751
16:43055
17:47127
18:41243
19:41837
20:32207
21:11965