- 随机数介绍
在程序开发中,我们经常会用到随机数。譬如数字签名、数据加密、以及一些取样的场景下。但需要注意的是,许多开发语言API 所提供的随机函数并非真正意义上的随机,而是伪随机,至于原因,本文最后会进行解释。
- jdk中Random类
jdk中提供了Random类供我们使用
// within int range System.out.println(new Random().nextInt()); // [0,23) System.out.println(new Random().nextInt(23)); // [0.0,1.0) System.out.println(new Random().nextDouble()); // [0.0,1.0) System.out.println(new Random().nextDouble()); // generate true or false with equal probability System.out.println(new Random().nextBoolean());
- 种子
值得注意的是Random类中提供了另外一个带参构造函数 Random(long seed)
我们输入下面代码
Random random1 = new Random(23); for (int i = 0; i < 5; i++) { System.out.println(random1.nextInt()); } Random random2 = new Random(23); for (int i = 0; i < 5; i++) { System.out.println(random2.nextInt()); } 某次结果如下 -1150482841 1434614297 156591366 825130495 960144037 ------------- -1150482841 1434614297 156591366 825130495 960144037
有读者可能感到困惑,为什么两个Random 独立生成出的数字序列完全相同,对,不必疑惑!即使生成10000次,他们生成的随机数序列也完全相同!
这也是本文开头所说的伪随机。
大部分的开发语言中,随机数产生都采用了线性同余法
数学表达式如下
X(n+1) = (a * X(n) + c) % m
所以,随机数值是其实是通过公式算出来的。当你在构造不同的Random类时传入了相同的种子(Seed)时候,必然会得到相同的数字序列!
我们观察下jdk产生随机数的核心函数:
protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); }
其中(oldseed * multiplier + addend) & mask就是采用了线性同余法。只不过jdk开发者进行了一些处理而已。
而我们使用无参构造函数时,会默认使用时间作为种子,所以,即使定义了若干Random 类,他们产生的随机数序列也不会相同。
好了,今天学习就到这里,下次我们讲讲 Apache Commons Lang 中的 RandomUtils类
时间: 2024-11-10 21:13:28