我点击按钮多次执行以下代码:
int UP = 4;
Log.println(Log.DEBUG, "random", new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
+ new Random().nextInt(UP) + " "
);
我对在日志中得到这个感到非常惊讶:
04-07 21:26:36.659: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:37.059: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:37.429: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:37.789: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:38.119: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:38.429: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:38.739: D/random(15640): 1 1 1 1 1 1 1 1
04-07 21:26:39.019: D/random(15640): 2 2 2 2 2 2 2 2
04-07 21:26:39.319: D/random(15640): 2 2 2 2 2 2 2 1
04-07 21:26:39.599: D/random(15640): 2 1 1 1 1 1 1 1
- 当然,这些序列绝对是非随机的。
我知道,我应该创建一个Random
对象的实例,并根据需要多次调用它nexInt()
。但是Java每次都会更改静态种子数随机实例由Random()
构造函数创建:
public Random() {
this(++seedUniquifier + System.nanoTime());
}
private static volatile long seedUniquifier = 8682522807148012L;
所以生成的序列应该是随机的,无论我们是使用一个对象还是每次使用新对象。但出于某种原因,他们不是。
我决定继续我的研究,用不同的论点调用nextInt()
。而我接下来看到的,让我更加惊讶。我注意到每当我选择UP
常量为2 的幂时,new Random().nextInt(UP)
的结果仍然绝对是非随机的,但是当我选择不同的数字时,一切都很好。
UP = 8:
04-07 21:43:47.169: D/random(15789): 5 4 4 4 4 5 5 5
04-07 21:43:47.809: D/random(15789): 7 7 7 7 7 7 7 7
04-07 21:43:48.249: D/random(15789): 6 7 7 7 7 6 6 6
04-07 21:43:48.619: D/random(15789): 6 6 6 6 6 6 6 6
04-07 21:43:48.999: D/random(15789): 5 5 5 5 5 5 4 4
04-07 21:43:49.399: D/random(15789): 4 4 4 4 4 4 4 4
UP = 32:
04-07 21:45:27.979: D/random(15888): 16 15 15 14 15 15 15 24
04-07 21:45:28.329: D/random(15888): 23 23 23 24 24 24 24 21
04-07 21:45:28.549: D/random(15888): 22 20 20 20 20 21 21 21
04-07 21:45:28.849: D/random(15888): 31 31 31 31 31 31 29 29
04-07 21:45:29.329: D/random(15888): 27 28 28 28 26 26 26 26
但是对于UP = 10结果看起来是随机的,不是吗? -
04-07 21:47:02.189: D/random(15983): 8 4 1 9 6 6 4 2
04-07 21:47:02.639: D/random(15983): 7 5 3 0 7 5 2 0
04-07 21:47:02.999: D/random(15983): 3 9 6 4 1 8 6 3
04-07 21:47:03.379: D/random(15983): 5 4 1 8 6 3 0 8
04-07 21:47:03.669: D/random(15983): 5 1 8 6 3 3 1 8
04-07 21:47:03.989: D/random(15983): 3 3 1 4 1 8 6 3
04-07 21:47:04.269: D/random(15983): 6 6 3 1 8 5 3 0
所以我只有一个问题:任何人都知道发生了什么以及为什么?为什么nextInt(2^N)
获得的结果是非随机的,而使用任何其他参数获得的结果非常好?
==================================
更新。评论中的家伙说,桌面JVM结果在作为nextInt()
参数传递的数字上是随机的。那么描述的行为仅针对Android吗?
更新2。答案标记为此问题的最佳答案,尤其是下面的讨论,可以清楚地说明发生了什么。
答案 0 :(得分:1)
来自nextInt()
上的Java文档:
public int nextInt(int n)统一返回伪随机数 在0(包括)和指定值之间分配int值 (独占的),从这个随机数生成器的序列中提取。该 nextInt的一般契约是指定的一个int值 范围是伪随机生成并返回的。所有可能的int 以(近似)相等的概率产生值。方法 nextInt(int n)由Random类实现,如下所示:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
*if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);*
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
注意当n是2的幂时的特定情况。无论你传入nextInt
的n是什么,用相同的输入位调用函数next
,return语句就是简单的n次,所以每当你发出2次请求的权力时,它就会变得非常确定。