Java:Random函数及其种子的作用
伪随机(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函数及其种子的作用的更多相关文章
- Java Random函数
Java中存在着两种Random函数: 1.java.lang.Math.Random: 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...
- JAVA中的Random()函数
Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...
- tips:Java的Random类和Random函数
tips:Java的Random类和Random函数! 随机数是一个很有趣的东西,在java中可以通过下面这2种方法得到: (1)Random类: Random类是java.util.Random这个 ...
- Java - 经常使用函数Random函数
http://blog.csdn.net/pipisorry/article/details/44411541 Random()函数生成随机数 java.util.Random 在Java的API帮助 ...
- random函数
Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...
- random函数详解
1. 随机函数 Math.random() Math.random(); 取值范围是 [ 0.0,1.0 ) 的左闭右开区间.具体源代码如下所示: Math.random()是生成0~ ...
- java Random类和Math.Rondom
Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取 ...
- JAVA Random 详解
Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范 ...
- C#Random函数在循环中每次获取一样的值
首先需要了解一点Random函数的随机生成是和当前时间有关系,如果在短时间生成随机数,就会导致随机数生成出来是相同的. 不过我们可以在每次随机时指定一个Seed种子值,这样在循环里就可以每次获取不一样 ...
随机推荐
- Docker入门系列之三:如何将dockerfile制作好的镜像发布到Docker hub上
这个系列的前两篇文章,我们已经把我们的应用成功地在Docker里通过nginx运行了起来,并且用dockerfile里制作好了一个镜像. Docker入门系列之一:在一个Docker容器里运行指定的w ...
- Jmeter入门12 __time函数 jmeter获取当前系统时间
有的接口要传递当前的日期或时间,可以用__time()函数获取当前时间 ${__time()} 当前时间到计算机元年的毫秒数 ${__time(时间格式)} 以预定的格式显示当前时间 请求示例: ...
- 密钥导出函数(Key derivation function)
在密码学中,密钥导出函数(KDF)使用伪随机函数从秘密值(eg.主密钥)导出一个或多个密钥.KDF可用于将密钥扩展到更长的密钥或获得所需格式的密钥(eg.将作为Diffie-Hellman密钥交换的结 ...
- Codeforces Round #422 (Div. 2)
Codeforces Round #422 (Div. 2) Table of Contents Codeforces Round #422 (Div. 2)Problem A. I'm bored ...
- 【[ZJOI2010]网络扩容】
题目 第一问直接板子敲上去 第二问并不明白直接在残量网络上加边的神仙做法 非常显然我们需要让流量加\(k\),那么我们就使得网络里的总流量为\(maxf+k\),\(maxf\)是第一问求出来的最大流 ...
- position中需要注意的地方
relative是相对元素本身位置进行移位,但不会改变本身位置的大小 本身的位置 移位后,可以看到,p5的位置还是在那,并不会自动往上走,也就是p2的位置原来所占据的位置不变的.不会因为偏移而改变布局 ...
- 【转】android:windowSoftInputMode属性详解
android:windowSoftInputMode activity主窗口与软键盘的交互模式,可以用来避免输入法面板遮挡问题,Android1.5后的一个新特性. 这个属性能影响两件事情: [一] ...
- 【转】Android Activity原理以及其子类描述,androidactivity
Android Activity原理以及其子类描述,androidactivity 简介 Activity是Android应用程序组件,实现一个用户交互窗口,我们可以实现布局填充屏幕,也可以实 ...
- 用keytool制作证书并在tomcat配置https服务(四)
用keytool制作证书并在tomcat配置https服务(一) 用keytool制作证书并在tomcat配置https服务(二) 用keytool制作证书并在tomcat配置https服务(三) 上 ...
- 手机移动端 web整合
meta基础知识 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...