Random.nextInt(int)[略微偏]

Ale*_*rev 10 java random

也就是说,它将永远不会连续生成超过16个偶数,并带有一些特定upperBound参数:

Random random = new Random();

int c = 0;
int max = 17;
int upperBound = 18;

while (c <= max) {
    int nextInt = random.nextInt(upperBound);
    boolean even = nextInt % 2 == 0;
    if (even) {
        c++;
    } else {
        c = 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,代码将永远循环,而当upperBound例如是16时,它会很快终止.

这种行为的原因是什么?方法的javadoc中有一些注释,但我没理解它们.


UPD1:代码似乎以奇数上限终止,但可能会遇到偶数


UPD2:我修改了代码以捕获c评论中建议的统计信息:

Random random = new Random();

int c = 0;
long trials = 1 << 58;
int max = 20;
int[] stat = new int[max + 1];

while (trials > 0) {
    while (c <= max && trials > 0) {
        int nextInt = random.nextInt(18);
        boolean even = nextInt % 2 == 0;
        if (even) {
            c++;
        } else {
            stat[c] = stat[c] + 1;
            c = 0;
        }
        trials--;
    }
}

System.out.println(Arrays.toString(stat));
Run Code Online (Sandbox Code Playgroud)

现在它试图20在行中达到平衡 - 以获得更好的统计数据,而且upperBound仍然存在18.

事实证明结果令人惊讶:

[16776448, 8386560, 4195328, 2104576, 1044736, 
 518144, 264704, 132096, 68864, 29952, 15104, 
 12032, 1792, 3072, 256, 512, 0, 256, 0, 0]
Run Code Online (Sandbox Code Playgroud)

首先它按预期减少2倍,但请注意最后一行!在这里它变得疯狂,捕获的统计数据似乎是完全奇怪的.

这是一个对数比例的条形图:

c统计

如何c获得17256倍的价值又是另一个谜

ted*_*ted 5

http://docs.oracle.com/javase/6/docs/api/java/util/Random.html:

该类的实例用于生成伪随机数流.该类使用48位种子,使用线性同余公式进行修改.(参见Donald Knuth,计算机程序设计的艺术,第3卷,第3.2.1节.)

如果使用相同的种子创建两个Random实例,并且对每个实例都进行相同的方法调用序列,则它们将生成并返回相同的数字序列.[...]

它是随机数生成器.这意味着您实际上并没有掷骰子,而是使用公式根据当前随机值计算下一个"随机"值.为了创造随机化的假象,seed使用了a .种子是公式中用于生成随机值的第一个值.

显然javas随机实现("公式"),连续生成不超过16个偶数.

这种行为是seed通常用时间初始化的原因.根据您何时启动程序,您将获得不同的结果.

这种方法的好处是可以产生可重复的结果.如果你有一个游戏生成"随机"地图,你可以记住种子,如果你想再次播放它,重新生成相同的地图.

对于真随机数,某些操作系统提供了特殊设备,可以从外部事件(如鼠标移动或网络流量)中生成"随机性".但是我不知道如何利用java进入那些.

从用于secureRandom的Java doc :

许多SecureRandom实现采用伪随机数生成器(PRNG)的形式,这意味着它们使用确定性算法从真正的随机种子生成伪随机序列.其他实现可以产生真正的随机数,而其他实现可以使用两种技术的组合.

需要注意的是SecureRandom的确实保证真正的随机数,无论是.

为什么改变种子没有帮助

假设随机数只有0-7的范围.现在我们使用以下公式生成下一个"随机"数字:

 next = (current + 3) % 8
Run Code Online (Sandbox Code Playgroud)

顺序变成了0 3 6 1 4 7 2 5.

如果你现在拿种子3你所做的就是改变起点.

在这个仅使用前一个值的简单实现中,每个值只能在序列换行并再次启动之前出现一次.否则会有一个无法到达的部分.

想象一下序列0 3 6 1 3 4 7 2 5.这些数字0,4,7,2 and 5永远不会产生多次(因为它们可能永远不会产生种子),因为一旦序列循环3,6,1,3,6,1,....

可以将简化的伪随机数生成器视为范围内所有数字的排列,并使用种子作为起点.如果它们更高级,则必须使用可能多次出现相同数字的列表替换排列.

更复杂的发生器可以具有内部状态,允许在序列中多次出现相同的数字,因为状态允许发生器知道继续的位置.