【伪随机数】
真正意义上的随机数(或者随机事件)在某次产生过程中是按照实验过程中表现的分布概率随机产生的,其结果是不可预测的,是不可见的。
而计算机中的随机函数是按照一定算法模拟产生的,其结果是确定的,是可见的。我们可以这样认为这个可预见的结果其出现的概率是100%。所以用计算机随机函数所产生的“随机数”并不随机,是伪随机数。
【二项分布】
若某事件概率为p,每次试验相互独立,结果只有发生与不发生两种(伯努利实验),现重复试验n次,则该事件发生k次的概率为:P=C(k,n) * (p^k) * ((1-p)^(n-k))其中C(k,n)表示组合数,即从n个事物中拿出k个的方法数。
当n很大p很小时,可以取np=λ则趋近于泊松分布。
【泊松分布】
在实际事例中,当一个随机事件,例如某电话交换台收到的呼叫、来到某公共汽车站的乘客等等,以固定的平均瞬时速率λ(或称密度)随机且独立地出现时,那么这个事件在单位时间(面积或体积)内出现的次数或个数就近似地服从泊松分布。
例子:已知某家小杂货店,平均每周售出2个水果罐头。请问该店水果罐头的最佳库存量是多少?假定不存在季节因素,可以近似认为,这个问题满足以下三个条件:(1)顾客购买水果罐头是小概率事件。(2)购买水果罐头的顾客是独立的,不会互相影响。(3)顾客购买水果罐头的概率是稳定的。在统计学上,只要某类事件满足上面三个条件,它就服从"泊松分布"。
各个参数的含义:P(X=k)= (e^(-λ)) * (λ^k) / k!
P:每周销售k个罐头的概率。X:水果罐头的销售变量。k:X的取值(0,1,2,3...)。
λ:每周水果罐头的平均销售量,是一个常数,即速率为2。
当λ很大时,则趋近于正态分布。(正态分布是连续的,但泊松分布是离散的。)
【生成伪随机数】
一般地,伪随机数的生成方法主要有以下3种:
(1) 直接法(Direct Method),根据分布函数的物理意义生成。缺点是仅适用于某些具有特殊分布的随机数,如二项式分布、泊松分布。
(2) 逆转法(Inversion Method),假设U服从[0,1]区间上的均匀分布,令X=F-1(U),则X的累计分布函数(CDF)为F。该方法原理简单、编程方便、适用性广。
(3)接受拒绝法(Acceptance-Rejection Method):假设希望生成的随机数的概率密度函数(PDF)为f,则首先找到一个PDF为g的随机数发生器与常数c,使得伪随机数发生器f(x)≤cg(x),然后根据接收拒绝算法求解。由于算法平均运算c次才能得到一个希望生成的随机数,因此c的取值必须尽可能小。显然,该算法的缺点是较难确定g与c。
因此,伪随机数生成器(PRNG)一般采用逆转法,其基础是均匀分布,均匀分布PRNG的优劣决定了整个随机数体系的优劣。
【均匀分布】F(x)=(x-a)/(b-a),a≤x≤b,即一维的比例关系。
【Java实现伪随机数的源码】
// nextInt() -> 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));
}
//返回nextseed的16位以上的高位
//seed.compareAndSet(oldseed, nextseed)是线程安全检查,并把nextseed赋值给oldseed
//nextseed的计算为(oldseed * 25214903917 + 11) & ((1L << 48) - 1),即乘法加法后,除以281474976710656取余数
//没搞明白multiplier和addend的值有什么蹊跷。简单来说就是乘以multiplier加上addend然后对mask取余。
【参考资料】度娘,维基百科,JRE源码,及其他。