好吧,我承认我是在百度上google来的:Random rand = new Random(); 如果在实例化时没有传递任何参数,那么Java就会将当前时间作为随机数生成器的种子,并由此在程序没一次执行是都产生不同的输出。而如果在实例化时提供种子,就可以在每次执行程序时都生成相同的随机数,并且它的输出是可以验证的。(一) 例如:Random rand = new Random();int k = rand.nextInt()+1; 此时rand.nextInt() 或者 rand.nextInt(20) ,程序在每次运行时都会产生不同的随机数。(二) Random rand = new Random(47);(47被Bruce Eckel成为魔幻数字) 此时若 int k = rand.nextInt()+1; 每次程序的运行k都会得到相同的值。 若 int k = rand.nextInt(100)+1; 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和100(不包括)之间均匀分布的 int 值。nextInt 的常规协定是,伪随机地生成并返回指定范围中的一个 int 值。所有可能的 n 个 int 值的生成概率(大致)相同。此时每次程序运行 k 也会得到相同的值。
我找出了源代码(java.util.Random),(以int为例)如下: //private final AtomicLong seed; public Random(long seed){ this.seed=new AthomicLong(0L);//AthomicLong为原子变量类 setSeed(seed); } protected int next(int bits) {//线性同余算法 long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get();//get():获得当前值 //private final static long multiplier = 0x5DEECE66DL; //private final static long mask = (1L << 48) - 1; //private final static long addend = 0xBL; nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed));//如果 当前seed==oldseed,则以原子方式 //设置为给定的nextseed。 return (int)(nextseed >>> (48 - bits)); } public int nextInt(){ return next(32); } 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; } synchronized public void setSeed(long seed) { seed = (seed ^ multiplier) & mask;//seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); this.seed.set(seed);//void set(long value):设定为给定值; //private double nextNextGaussian; //private boolean haveNextNextGaussian = false; haveNextNextGaussian = false; } public void setSeed(long seed)使用单个 long 种子设置此随机数生成器的种子。setSeed 的常规协定是它更改此随机数生成器对象的状态,使其状态好像是刚刚使用参数 seed 作为种子创建它的状态一样. 注意另一个构造函数: public Random() { //private static volatile long seedUniquifier = 8682522807148012L; // static long System.nanoTime():返回最准确的可用系统计时器的当前值,以毫微秒为单位。 this(++seedUniquifier + System.nanoTime()); }
附 算法:线性同余法 一般计算机的随机数都是伪随机数,以一个真随机数(种子)作为初始条件,然后用一定的算法不停迭代产生随机数 1)将种子设为X0, 2)用一个算法X(n+1)= (a*X(n)+b) mod c产生X(n+1) 一般将c取得很大,可产生0到c-1之间的伪随机数 该算法的一个缺点是会出现循环。
这里有个简便、快捷的伪随机数函数,有兴趣的话可以看一下,具体的算法说明在代码注释中public class RandomGenerator { public static void main(String[] args) { for(int i = 0; i < 100; i++) { System.out.println(nextInt(10)); } }
public static int nextInt() { return xorShift(new Object().hashCode() ^ (int)System.nanoTime()); }
public static int nextInt(int limit) { return Math.abs(nextInt() ^ (int)System.nanoTime()) % limit; } /** * George Marsaglia, <i>Xorshift RNGs</i>, Journal of Statistical Software, * 8(14), 2003. pdf: http://www.jstatsoft.org/v08/i14/paper * * @param num * @return */ private static int xorShift(int num) { num ^= (num << 6); num ^= (num >>> 21); num ^= (num << 7); return num; } }
如果在实例化时没有传递任何参数,那么Java就会将当前时间作为随机数生成器的种子,并由此在程序没一次执行是都产生不同的输出。而如果在实例化时提供种子,就可以在每次执行程序时都生成相同的随机数,并且它的输出是可以验证的。(一) 例如:Random rand = new Random();int k = rand.nextInt()+1; 此时rand.nextInt() 或者 rand.nextInt(20) ,程序在每次运行时都会产生不同的随机数。(二) Random rand = new Random(47);(47被Bruce Eckel成为魔幻数字) 此时若 int k = rand.nextInt()+1; 每次程序的运行k都会得到相同的值。 若 int k = rand.nextInt(100)+1; 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和100(不包括)之间均匀分布的 int 值。nextInt 的常规协定是,伪随机地生成并返回指定范围中的一个 int 值。所有可能的 n 个 int 值的生成概率(大致)相同。此时每次程序运行 k 也会得到相同的值。
//private final AtomicLong seed;
public Random(long seed){
this.seed=new AthomicLong(0L);//AthomicLong为原子变量类
setSeed(seed);
}
protected int next(int bits) {//线性同余算法
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();//get():获得当前值
//private final static long multiplier = 0x5DEECE66DL;
//private final static long mask = (1L << 48) - 1;
//private final static long addend = 0xBL;
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));//如果 当前seed==oldseed,则以原子方式 //设置为给定的nextseed。
return (int)(nextseed >>> (48 - bits));
}
public int nextInt(){
return next(32);
}
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;
}
synchronized public void setSeed(long seed) {
seed = (seed ^ multiplier) & mask;//seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
this.seed.set(seed);//void set(long value):设定为给定值;
//private double nextNextGaussian;
//private boolean haveNextNextGaussian = false;
haveNextNextGaussian = false;
}
public void setSeed(long seed)使用单个 long 种子设置此随机数生成器的种子。setSeed 的常规协定是它更改此随机数生成器对象的状态,使其状态好像是刚刚使用参数 seed 作为种子创建它的状态一样.
注意另一个构造函数:
public Random() {
//private static volatile long seedUniquifier = 8682522807148012L;
// static long System.nanoTime():返回最准确的可用系统计时器的当前值,以毫微秒为单位。
this(++seedUniquifier + System.nanoTime());
}
一般计算机的随机数都是伪随机数,以一个真随机数(种子)作为初始条件,然后用一定的算法不停迭代产生随机数
1)将种子设为X0,
2)用一个算法X(n+1)= (a*X(n)+b) mod c产生X(n+1)
一般将c取得很大,可产生0到c-1之间的伪随机数
该算法的一个缺点是会出现循环。
for(int i = 0; i < 100; i++) {
System.out.println(nextInt(10));
}
}
public static int nextInt() {
return xorShift(new Object().hashCode() ^ (int)System.nanoTime());
}
public static int nextInt(int limit) {
return Math.abs(nextInt() ^ (int)System.nanoTime()) % limit;
} /**
* George Marsaglia, <i>Xorshift RNGs</i>, Journal of Statistical Software,
* 8(14), 2003. pdf: http://www.jstatsoft.org/v08/i14/paper
*
* @param num
* @return
*/
private static int xorShift(int num) {
num ^= (num << 6);
num ^= (num >>> 21);
num ^= (num << 7);
return num;
}
}
Random 使用的是线性同余算法,至于为什么有随机性,这是数论中知识的。要证明这个算法的随机性,需要一定的数论知识。另外,数论是数学中的一个分支,对于非数学专业的本科阶段来说不会学习到有关数论的知识,所以建议楼主不用花心细去研究了。