java伪随机数

 java的随机数我们用的很多,但是java随机数的发生器是什么原理呢?一直没有搞明白,最近搞了一下贴出来看看

概念

1、随机数:新的随机数与上一个数无关,不可追溯,不可预测

2、随机数发生器:产生随机数的方法

3、真正的随机数:真正的随机数一般都是由物理现象产生的

4、伪随机数:是由固定的、可以重复计算的算法产出

伪随机数发生器的评判标准

1.符合统计学的平均性---均匀性

2.相同序列的概率非常低---随机性

3.不应该能够从一段序列猜测出随机数发生器的工作状态或者下一个随机数---不可预测

4.不应该从随机数发生器的状态能猜测出随机数发生器以前的工作状态---不可回溯

一般用的随机数发生器满足1和2就可以了,对密码学上使用的随机数发生器还需要满足3和4

用的比较多的是线性同余法

线性同余方法(LCG)

 同余:两个整数a、b,若它们除以整数m所得的余数相等,则称a与b对于模m同余

数学表示为:a ≡ b (mod m)

LCG:根据递归公式

   xn+1≡ (axn+ c ) (mod m)   a,c,m是常数

给定x0产生的随机数列{xi}称为LCG{a,c,m,x0}序列

当c ≠ 0时为混合同余法(MLCG)

当c = 0时为乘同余法(PMLCG)

JAVA API中用的是混合同余法

LCG序列的周期性

   xn+1≡ (7xn+ 7 ) (mod 10) x0=7时得到

  的序列是:

7,6,9,0,7,6,9,0,7…..

从列子中可以看出LCG序列是有周期性的,我们把xk=x0时的最小正整数k称为序列的周期d,LCG序列的最大周期不可能大于除数m,当d=m时,称该序列达到满周期(最大周期)

LCG达到满周期的条件

要令LCG达到满周期,应符合以下条件:

1.c,m互质

2.m的所有质因子的积能整除a-1

3.若m是4的倍数,a-1也是

4.a,c,x0都比m小

5.a,c是正整数

证明(混合线性同余发生器的周期分析.pdf)~~~

达到满周期说明LCG序列是均匀的,并且不易重复(取决于m的大小),因为达到满周期说明一个循环里每一个数据都被取到,是均匀的,并且在一个周期内都不会重复

LCG的效能

 效能:具有满周期的线性同余序列的效能被定义使得(a-1)s 0 (mod m)的最小整数s

当满足满周期的条件时,s总是存在的,因为b是m的每个素数的倍数

根据经验和实际检验的效果当效能达到5时才能保证随机性

证明~~请参看《计算机程序设计艺术(第二卷)》的3.2.1.3节

JAVA的随机数

常用的随机数类java.util.Random(Math.random也使用此类),使用混合线性同余法生成随机数

混合线性同余法主要的4个初始化参数:

a=25214903917(乘数multiplier)

c=11(增量addend)

m=2^48(模数mask)

x0=种子seed

其中a、c、m满足满周期的条件,同时效能是24,说明均匀性和随机性都很好

因为 a,c,m 的参数都一样,所以相同的种子就会产生相同的随机序列

默认的种子是用时间+增长序列,同一个jvm里random的初始种子几乎不会重复,请看源码:

public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;

 这个类中最重要的方法是

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));
}

 从源码中我们可以看出,random只产生int型的随机数,并且保证了同一个对象即使在多线程情况下也不会产生一样的随机数,产生的int随机数是从高位开始截取的,也就是保留高位,去掉低位

 

nextInt方法

 

public int nextInt() {
    return next(32);
}
 

 

nextLong方法是两个nextInt加起来的

 

public long nextLong() {
    return ((long)(next(32)) << 32) + next(32);
}
 

 

nextDouble()方法是两个27位的随机数相加,然后除以2^54

public double nextDouble() {
    return (((long)(next(26)) << 27) + next(27)) / (double)(1L << 53);
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值