今天在微博上到一篇如何使用随机数的文章,让我回忆起刚上大一时学C语言时,书后有道调用rand()函数的练习题,当时觉得好神奇,想知道它是怎么实现的,大二时候学Java又遇到了random()函数,恰巧当时上机课我有机会问老师,遗憾的是老师只是告诉我那是伪随机数,课后查查资料才了解。如今来一篇关于随机数发生器博文来回忆一下神奇的随机数。
众所周知,我们平时所使用的无论什么编程语言都会提供一个随机数函数,而且它是伪随机数(Pseudo Random Number),它是由算法计算得出的,是可以预测的,也就是说当随机种子相同时,对于同一个随机函数,得出的随机数列是固定不变的;与之对应的就是真随机数(True Random Number)它是真正的随机数,无法预测且无周期性;还有一种是产生随机数的发生器是密码学伪随机数发生器(Cryptographically Secure Pseudo-Random Number Generator)常用的算法有 MD5 ,SHA1 等标准,这里不做过多讨论,说说最基本的前两种:
一、真随机数发生器
像无法实现永动机一样,想要实现真随机数靠程序是永远无法实现的,很多情况下只能看老天的眼色,比如布朗运动,量子效应,放射性衰变等。第一个真随机数发生器是1955年由Rand公司创造的,而在1999年,intel发布Intel810芯片组时,就配备了硬件随机数发生器,基于IntelRNG的真随机数生成器可以生成满足独立性和分布均匀性的真随机数,目前大部分芯片厂商都集成了硬件随机数发生器,只要安装相应驱动,了解读取寄存器地址,可以直接调用发生器。Intel810RNG的原理大概是:利用热噪声(是由导体中电子的热震动引起的)放大后,影响一个由电压控制的振荡器,通过另一个高频振荡器来收集数据。TRNG的类型主要有:
1.基于电路的TRNG:
i.振荡器采样:就是上述Intel采用的方式。
ii.直接放大电路噪声:利用电路中各种噪声,如上述的热噪声作为随机源,由于强度小,所以先要对其放大,然后对一定时间内超过阈值的数据进行统计,这样就产生的随机数。.
iii.电路亚稳态:亚稳态表示触发器无法在规定时间内达到一个可确认状态,一定条件下,触发器达到两个稳态的几率为50%,所以先使电路进入亚稳态,之后根据状态转化为随机数。
iv.混沌电路:不可预测,对初始条件的敏感的依赖性。以及混沌电路在芯片中易于实现的特点,可以产生效果不错的随机数。
2.基于其他物理源的TRNG
如宇宙射线,粒子衰变,空气噪声等作为随机源,来产生随机数。
3.其他物理信息TRNG
人为可以产生随机数吗?当然能!听说一个HR拆选简历的方式是往天上一扔,掉在桌子上的简历就通过,这个HR确认懂随机啊,而且是真随机。这类随机生活中随处可见,掷骰子,抓麻将,或者统计一个月内帝都PM2.5的数值。
二、伪随机数发生器
通过程序得到的随机数无论什么算法都一定是通过递推公式得到的序列,这本身就违反了随机的定义,所以它们都不是真正的随机数。伪随机数中一个很重要的概念就是“种子”,种子决定了随机数的固定序列,例如在C语言rand函数得到的序列每次都是相同的,如果想得到不同序列需要调用srand设置种子;同理在Java中 new Random(1)的构造函数参数来设置种子。下面介绍生成PRNG的几种常见方法:
1.取中法:
i.平方取中法:
这个方法是由冯·诺伊曼在1946年提出的,思想很简单:
public class CustomRandom { static final int FIGURES = 10000; static long mRandom; public static void main(String[] args) { long seed = System.currentTimeMillis(); mRandom = seed % FIGURES; for (int i = 0; i < 10; i++) System.out.println(getRandom(seed)); } private static long getRandom(long seed) { return mRandom = (mRandom * mRandom / (long) Math.pow(10, 5/2)) % FIGURES; } }
ii:常数取中法
iii:乘法取中法:
2.同余法
public class CustomRandom { static final int A = 3; static final int M = (1 << 31) - 1 ; private static long mRandom; public static void main(String[] args) { mRandom = System.currentTimeMillis() / Integer.MAX_VALUE; for (int i = 0; i < 10; i++) { mRandom = (mRandom * A) % M; System.out.println(mRandom); } } }除此之外还有二次同余,三次同余等,原理差不多。
3.移位法:
public class CustomRandom { static final int N = 5; static long mRandom; public static void main(String[] args) { long mRandom = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { mRandom = Math.abs((mRandom >> N) + (mRandom << N)); System.out.println(mRandom); } } }
4.梅森旋转算法
梅森旋转算法(Mersenne twister)是一个伪随机数生成算法。由松本真和西村拓士在1997年开发,基于有限二进制字段上的矩阵线性地鬼。可以快速产生高质量的伪随机数, 修正了古典随机数发生算法的很多缺陷。
下面的一段伪代码使用MT19937算法生成范围在[0, 232 − 1]的均匀分布的32位整数
//创建一个长度为624的数组来存储发生器的状态
int[0..623] MT
int index = 0
//用一个种子初始化发生器
function initialize_generator(int seed) {
i := 0
MT[0] := seed
for i from 1 to 623 { // 遍历剩下的每个元素
MT[i] := last 32 bits of(1812433253 * (MT[i-1] xor (right shift by 30 bits(MT[i-1]))) + i) // 0x6c078965
}
}
// Extract a tempered pseudorandom number based on the index-th value,
// calling generate_numbers() every 624 numbers
function extract_number() {
if index == 0 {
generate_numbers()
}
int y := MT[index]
y := y xor (right shift by 11 bits(y))
y := y xor (left shift by 7 bits(y) and (2636928640)) // 0x9d2c5680
y := y xor (left shift by 15 bits(y) and (4022730752)) // 0xefc60000
y := y xor (right shift by 18 bits(y))
index := (index + 1) mod 624
return y
}
// Generate an array of 624 untempered numbers
function generate_numbers() {
for i from 0 to 623 {
int y := (MT[i] & 0x80000000) // bit 31 (32nd bit) of MT[i]
+ (MT[(i+1) mod 624] & 0x7fffffff) // bits 0-30 (first 31 bits) of MT[...]
MT[i] := MT[(i + 397) mod 624] xor (right shift by 1 bit(y))
if (y mod 2) != 0 { // y is odd
MT[i] := MT[i] xor (2567483615) // 0x9908b0df
}
}
}
这里有完整的源码实现:http://www.cs.gmu.edu/~sean/research/mersenne/MersenneTwister.java==================================================================================================
作者:nash_ 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/zmazon/article/details/17383521
===================================================================================================