随机均匀分布

DaJ*_*kal 15 java random

我知道如果我使用Java的Random生成器,使用nextInt生成数字,数字将是均匀分布的.但是如果我使用2个Random实例会发生什么,用两个Random类生成数字.这些数字是否均匀分布?

Gro*_*uez 9

每个Random实例生成的数字将是均匀分布的,因此如果组合两个Random实例生成的随机数序列,它们也应该均匀分布.

请注意,即使得到的分布是均匀的,您也可能需要注意种子以避免两个生成器的输出之间的相关性.如果使用默认的no-arg构造函数,则种子应该已经不同了.来源代码java.util.Random:

private static volatile long seedUniquifier = 8682522807148012L;

public Random() { this(++seedUniquifier + System.nanoTime()); }
Run Code Online (Sandbox Code Playgroud)

如果您明确设置种子(通过使用Random(long seed)构造函数或调用setSeed(long seed)),您需要自己处理.一种可能的方法是使用随机数生成器为所有其他生成器生成种子.

  • @Mike:错了.读取和写入非易失性long是**不保证是原子的,你当然可以看到半写值.对于长期标记为"volatile"的情况并非如此.请参阅Java语言规范的第17.7节(http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7).您也可以通过简单的测试程序轻松检查.但是,关于读取 - 修改 - 写入周期不是以原子方式发生的其他注释是正确的. (2认同)

Mik*_*ark 9

好吧,如果你Random用相同的值对两个实例进行种子处理,你肯定不会得到高质量的离散均匀分布.考虑最基本的情况,从字面上打印两次完全相同的数字(不会比那更少随机...):

public class RngTest2 {
    public static void main(String[] args) throws Exception {
        long currentTime = System.currentTimeMillis();
        Random r1 = new Random(currentTime);
        Random r2 = new Random(currentTime);
        System.out.println(r1.nextInt());
        System.out.println(r2.nextInt());
    }        
}
Run Code Online (Sandbox Code Playgroud)

但那只是一次迭代.如果我们开始增加样本量会发生什么?

以下是并排运行两个相同种子的RNG以生成2000个数字的分布的散点图:

替代文字

以下是运行单个RNG以分别生成2000个数字的分布:

替代文字

似乎很清楚哪种方法在该有限集上产生了更高质量的离散均匀分布.

现在几乎每个人都知道,如果你正在寻找高质量的随机性,那么用相同的种子播种两个RNG是一个坏主意.但这种情况确实让你停下来思考:我们已经创建了一个场景,其中每个RNG独立地发出相当高质量的随机性,但是当它们的输出组合时,它的质量显着降低(离散度较低).