伪随机(preundorandom):通过算法产生的随机数都是伪随机!!

只有通过真实的随机事件产生的随机数才是真随机!!比如,通过机器的硬件噪声产生随机数、通过大气噪声产生随机数

Random生成的随机数都是伪随机数!!!

是由可确定的函数(常用线性同余),通过一个种子(常用时钟),产生的伪随机数。这意味着:如果知道了种子,或者已经产生的随机数,都可能获得接下来随机数序列的信息(可预测性)

Random类拥有两个构造方法,用于实现随机数生成器:

Random( ) 构造一个随机数生成器
Random(long seed) 用种子seed构造一个随机数生成器

一、无参构造方法(不设置种子)

虽然表面上看我们未设置种子,但Random构造方法里有一套自己的种子生成机制,源码如下:

 /**
* Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely
* to be distinct from any other invocation of this constructor.
*/
public Random() {
this(seedUniquifier() ^ System.nanoTime());
} private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
} private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);

生成种子过程:(参考解密随机数生成器(二)——从java源码看线性同余算法)

1、获得一个长整形数作为“初始种子”(系统默认的是8682522807148012L)

2、不断与一个变态的数——181783497276652981L相乘(天知道这些数是不是工程师随便滚键盘滚出来的-.-)得到一个不能预测的值,直到 能把这个不能事先预期的值 赋给Random对象的静态常量seedUniquifier 。因为多线程环境下赋值操作可能失败,就for(;;)来保证一定要赋值成功

3、与系统随机出来的nanotime值作异或运算,得到最终的种子

nanotime算是一个随机性比较强的参数,用于描述代码的执行时间。源码中关于nanotime的描述(部分):

/**
* Returns the current value of the running Java Virtual Machine's
* high-resolution time source, in nanoseconds.
*
* <p>This method can only be used to measure elapsed time and is
* not related to any other notion of system or wall-clock time.

二、有参构造方法(设置种子)

语法:Random ran = Random(long seed)

有参构造方法的源码如下:

 /**
* Creates a new random number generator using a single {@code long} seed.
* The seed is the initial value of the internal state of the pseudorandom
* number generator which is maintained by method {@link #next}.
*
* <p>The invocation {@code new Random(seed)} is equivalent to:
* <pre> {@code
* Random rnd = new Random();
* rnd.setSeed(seed);}</pre>
*
* @param seed the initial seed
* @see #setSeed(long)
*/
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
} private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}

其中的multiplier和mask都是定值:

  private static final long multiplier = 0x5DEECE66DL;

  private static final long mask = (1L << 48) - 1;

三、代码测试

分别采用有参和无参两种方法,生成[0, 100)内的随机整数,各生成五组,每组十个随机数:

 import java.util.Random;

 public class RandomTest {
public static void main(String[] args) {
RandomTest rt = new RandomTest();
rt.testRandom();
} public void testRandom(){
System.out.println("Random不设置种子:");
for (int i = 0; i < 5; i++) {
Random random = new Random();
for (int j = 0; j < 10; j++) {
System.out.print(" " + random.nextInt(100) + ", ");
}
System.out.println("");
} System.out.println(""); System.out.println("Random设置种子:");
for (int i = 0; i < 5; i++) {
Random random = new Random();
random.setSeed(100);
for (int j = 0; j < 10; j++) {
System.out.print(" " + random.nextInt(100) + ", ");
}
System.out.println("");
}
}
}

运行结果如下:

结论:

虽然二者都是伪随机,但是,无参数构造方法(不设置种子)具有更强的随机性,能够满足一般统计上的随机数要求。使用有参的构造方法(设置种子)无论你生成多少次,每次生成的随机序列都相同,名副其实的伪随机!!

Java:Random函数及其种子的作用的更多相关文章

  1. Java Random函数

    Java中存在着两种Random函数: 1.java.lang.Math.Random: 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...

  2. JAVA中的Random()函数

    Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...

  3. tips:Java的Random类和Random函数

    tips:Java的Random类和Random函数! 随机数是一个很有趣的东西,在java中可以通过下面这2种方法得到: (1)Random类: Random类是java.util.Random这个 ...

  4. Java - 经常使用函数Random函数

    http://blog.csdn.net/pipisorry/article/details/44411541 Random()函数生成随机数 java.util.Random 在Java的API帮助 ...

  5. random函数

    Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...

  6. random函数详解

    1. 随机函数  Math.random() Math.random();    取值范围是  [ 0.0,1.0 )  的左闭右开区间.具体源代码如下所示:   Math.random()是生成0~ ...

  7. java Random类和Math.Rondom

      Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取 ...

  8. JAVA Random 详解

    Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...

  9. C#Random函数在循环中每次获取一样的值

    首先需要了解一点Random函数的随机生成是和当前时间有关系,如果在短时间生成随机数,就会导致随机数生成出来是相同的. 不过我们可以在每次随机时指定一个Seed种子值,这样在循环里就可以每次获取不一样 ...

随机推荐

  1. bzoj5000 OI树

    Description 几天之后小跳蚤即将结束自己在lydsy星球上的旅行.这时,lydsy人却发现他们的超空间传送装置的能量早在小跳蚤通过石板来到lydsy星球时就已经消耗光了.这时,小跳蚤了解到自 ...

  2. Codeforces Round #422 (Div. 2)

    Codeforces Round #422 (Div. 2) Table of Contents Codeforces Round #422 (Div. 2)Problem A. I'm bored ...

  3. Tinkoff Challenge - Final Round (ABC)

    A题:从两个保安中间那钞票 #include <bits/stdc++.h> using namespace std; int main() { int a,b,c; scanf(&quo ...

  4. POJ 1470 Closest Common Ancestors 【LCA】

    任意门:http://poj.org/problem?id=1470 Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000 ...

  5. IO缓冲区

    标准IO提供的三种类型的缓冲模式: (1)按块缓存:在填满缓冲区后才进行实际的设备读写操作 (2)按行缓存:指在接收到换行符('\n’)之前,数据都是先缓存在缓冲区的 (3)不缓存:允许你直接读写设备 ...

  6. 学习scala trait

      // 类接口,但是可以实现方法 // 作用 多重继承 trait traitA{ val tnum: Int def log(msg: String): Unit ={ println(" ...

  7. Trident中 FixedBatchSpout分析

    FixedBatchSpout 继承自 IBatchSpout IBatchSpout 方法 public interface IBatchSpout extends Serializable { v ...

  8. 在cengos中安装zabbix server/agent, 并创建一个简单demo

    添加zabbix更新源 rpm -ivh http://repo.zabbix.com/zabbix/2.4/rhel/6/x86_64/zabbix-release-2.4-1.el6.noarch ...

  9. 封装全局icon组件 svg (仿造element-ui源码)

    一.引入  svg-sprite-loader 插件 npm install svg-sprite-loader --save-dev vue-cli项目默认情况下会使用 url-loader 对sv ...

  10. 使用RMAN对数据文件进行恢复

    (1)备份数据库 在使用RMAN进行数据库恢复之前,先用RMAN进行全库备份 [oracle@redhat6 ~]$ rman target / Recovery Manager: Release : ...