java伪随机数
来源:互联网 发布:文明5 mac mod文件夹 编辑:程序博客网 时间:2024/05/29 14:47
首先,Math中的random方法其实是Random的nextDouble方法。
同余法(Congruential method)是很常用的一种随机数生成方法,在很多编程语言中有应用,最明显的就是java了,java.util.Random类中用的就是同余法中的一种——线性同余法(Linear congruential method),除此之外还有乘同余法(Multiplicative congruential method)和混合同余法(Mixed congruential method)。好了,现在我们就打开java的源代码,看一看线性同余法的真面目!
在Eclipse中输入java.util.Random,按F3转到Random类的源代码。这个类的一个实现是用来生成一串伪随机数。这个类用了一个48位的种子,被线性同余公式修改用来生成随机数。我们找到它的构造函数与相关的几个方法,里面包含了获得48位种子的过程:
private final static long multiplier = 0x5DEECE66DL;private final static long addend = 0xBL;private final static long mask = (1L << 48) - 1;public Random() { this(++seedUniquifier + System.nanoTime()); }private static volatile long seedUniquifier = 8682522807148012L;public Random(long seed) { this.seed = new AtomicLong(0L); setSeed(seed);}synchronized public void setSeed(long seed) { seed = (seed ^ multiplier) & mask; this.seed.set(seed); haveNextNextGaussian = false;}
这里分两种情况:1.采用默认种子,将seedUniquifier值(系统默认的8682522807148012L)与当前时间组合,生成一个新的种子。2.采用自定义种子,这时传什么值,种子就是多少。
再往下看,就是我们常用的得到随机数的方法了,我首先找到了最常用的nextInt()函数,代码如下:
public int nextInt() { return next(32);}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));}
这就是线性同余了,线性同余法是一个很古老的随机数生成算法,它的数学形式如下:Xn+1 = (a*Xn+c)(mod m)
其中,m>0,0<a<m,0<c<m
这里Xn这个序列生成一系列的随机数,X0是种子。随机数产生的质量与m,a,c三个参数的选取有很大关系。这些随机数并不是真正的随机,而是满足在某一周期内随机分布,这个周期的最长为m。根据Hull-Dobell Theorem,当且仅当:
1. c和m互素;
2. a-1可被所有m的质因数整除;
3. 当m是4的整数倍,a-1也是4的整数倍;
4. a,X0,c都比m小;
5.a,c都是正整数
周期为m。所以m一般都设置的很大,以延长周期。
现在我们回过头来看刚才的程序,注意这行代码:nextseed = (oldseed * multiplier + addend) & mask。和Xn+1=(a*Xn+c)(mod m)的形式很像有木有!其中multiplier和addend分别代表公式中的a和c,很好理解,但mask代表什么呢?其实,x & [(1L << 48)–1]与 x(mod 2^48)等价。我们将x对2^N取余操作希望达到的目的可以理解为:所有比2^N位(包括2^N那一位)全都为0,所有比2^N低的位保持原样。因此, x & ((2^N)-1)与x(mod 2^N)运算等价。讲明白了这个与运算的含义,我想上面那行代码的含义应该很明了了,就是线性同余公式的直接套用,其中a = 0x5DEECE66DL, c = 0xBL, m = 2^48,就可以得到一个48位的随机数,而且这个谨慎的工程师进行了迭代,增加结果的随机性。再把结果移位,就可以得到指定位数的随机数。
nextInt的另一种情况:
public int nextInt(int n) { if (n <= 0) throw new IllegalArgumentException("n must be positive"); if ((n & -n) == n) // i.e., n is a power of 2 return (int)((n * (long)next(31)) >> 31); int bits, val; do { bits = next(31); val = bits % n; } while (bits - val + (n-1) < 0); return val;}
可知范围是[0,n)。
- java简单伪随机数
- java 伪随机数安全性
- Java 伪随机数
- java伪随机数
- java 伪随机数安全性
- Java常用类:伪随机数生成类
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 伪随机数
- 基于mfc的对话框编程中,实现控件随对话框大小自动缩放以及通过滚动条实现控件移动功能
- 重温7 布局相关
- 基于C的2048游戏
- eqweqweqwe
- Java内部类的作用
- java伪随机数
- CentOS7安装MariaDB服务无法启动的问题
- Java中ListIterator和Iterator详解与辨析
- Drawable(分辨率)
- 现象的解释
- 【Javascript】——三大保存用户状态信息技术
- 思维导图示例
- JMeter事务控制器(Transaction controller)
- Count Complete Tree Nodes