JAVA util.Random创建随机数发生器,使用固定种子与不使用种子的区别

JAVA Random类在创建时有两种方式:无种子和指定种子。无种子时每次运行生成的随机数可能不同,而指定种子则会生成相同的序列。这是因为Random使用线性同余算法,相同种子产生相同序列。随机种子通常取系统时间以确保唯一性。当种子固定且在循环中使用时,每次循环内部的随机数生成取决于种子和算法,导致序列不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA Random随机数发生器在创建时有两种方法:

  1. 不指定随机数的构造方法Random()。
  2. 指定随机数的构造方法Random(seed)。

在第一种情况下:

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Random ra = new Random();
		System.out.println(ra.nextInt(10));

	}
}

运行三次

产生的结果分别是2,2,8。说明Random在每次运行过程中都会赋可能相同也可能不同随机种子值。

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Random ra = new Random(10);
		System.out.println(ra.nextInt(10));

	}
}

运行三次产生的结果分别为3,3,3。说明在设置相同的随机种子值的情况下,产生的随机数是相同的。因为Random类采用的是线性同余算法产生随机数,当确定唯一的种子时,会产生唯一的随机数。

为了产生不同的随机数可以将随机种子改为系统时间,程序如下:

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Random ra = new Random(System.currentTimeMillis());
		System.out.println(ra.nextInt(10));

	}
}

但是

当指定随机种子,循环生成10个随机数时,产生的结果却不同:

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Random ra = new Random(2);
		for (int i = 0; i < 10; i++) {
			System.out.println(ra.nextInt(10));
		}

	}
}

result0:
8
2
0
7
9
0
6
9
7
8
result1:
8
2
0
7
9
0
6
9
7
8

虽然两次运行的结果相同,但是,在指定随机种子的情况下,为什么每次循环生成的随机数却不同?

而将随机种子放在for循环中,则产生相同的结果:

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		// Random ra = new Random(2);
		for (int i = 0; i < 10; i++) {
			Random ra = new Random(2);
			System.out.println(ra.nextInt(10));
		}

	}
}

result:
8
8
8
8
8
8
8
8
8
8

其中的原因为:

 

在Java的API帮助文档中,总结了一下对这个Random()函数功能的描述:

1、java.util.Random类中实现的随机算法是伪随机,也就是有规则的随机,所谓有规则的就是在给定种(seed)的区间内随机生成数字;

2、相同种子数的Random对象,相同次数生成的随机数字是完全相同的;

3、Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率均等;

下面Random()的两种构造方法

1.Random():创建一个新的随机数生成器。

2.Random(long seed):使用单个 long 种子创建一个新的随机数生成器。

//获取当前时间的毫秒数作为随机数种子

long t = System.currentTimeMillis();

种子数只是随机算法的起源数字

value的值在变化,但是不同的循环,变化的值相同。

其中的到底什么和value变化有关?

大概可以从这个说法得出一些结论:

下面看这样一个C程序:

//rand01.c
#include<dos.h>

static unsigned int RAND_SEED;

unsigned int random(void)
{
RAND_SEED=(RAND_SEED*123+59)%65536;
return(RAND_SEED);
}

void random_start(void)
{
int temp[2];
movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
RAND_SEED=temp[0];
}

main()
{
unsigned int i,n;
random_start();
for(i=0;i<10;i++)
printf("%u\t",random());
printf("\n");
}

这个程序(rand01.c)完整地阐述了随机数产生的过程:
首先,主程序调用random_start()方法,random_start()方法中的这一句我很感兴趣:

movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);

这个函数用来移动内存数据,其中FP_SEG(far pointer to segment)是取temp数组段地址的函数,FP_OFF(far pointer to offset)是取temp数组相对地址的函数,movedata函数的作用是把位于0040:006CH存储单元中的双字放到数组temp的声明的两个存储单元中。这样可以通过temp数组把0040:006CH处的一个16位的数送给RAND_SEED。

random用来根据随机种子RAND_SEED的值计算得出随机数,其中这一句:

RAND_SEED=(RAND_SEED*123+59)%65536;

是用来计算随机数的方法,随机数的计算方法在不同的计算机中是不同的,即使在相同的计算机中安装的不同的操作系统中也是不同的。我在linux和windows下分别试过,相同的随机种子在这两种操作系统中生成的随机数是不同的,这说明它们的计算方法不同。

现在,我们明白随机种子是从哪儿获得的,而且知道随机数是怎样通过随机种子计算出来的了。那么,随机种子为什么要在内存的0040:006CH处取?0040:006CH处存放的是什么?

学过《计算机组成原理与接口技术》这门课的人可能会记得在编制ROM BIOS时钟中断服务程序时会用到Intel 8253定时/计数器,它与Intel 8259中断芯片的通信使得中断服务程序得以运转,主板每秒产生的18.2次中断正是处理器根据定时/记数器值控制中断芯片产生的。在我们计算机的主机板上都会有这样一个定时/记数器用来计算当前系统时间,每过一个时钟信号周期都会使记数器加一,而这个记数器的值存放在哪儿呢?没错,就在内存的0040:006CH处,其实这一段内存空间是这样定义的:

TIMER_LOW DW ? ;地址为 0040:006CH 
TIMER_HIGH DW ? ;地址为 0040:006EH 
TIMER_OFT DB ? ;地址为 0040:0070H

时钟中断服务程序中,每当TIMER_LOW转满时,此时,记数器也会转满,记数器的值归零,即TIMER_LOW处的16位二进制归零,而TIMER_HIGH加一。rand01.c中的

movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);

正是把TIMER_LOW和TIMER_HIGH两个16位二进制数放进temp数组,再送往RAND_SEED,从而获得了“随机种子”。

虽然java和C的运行机制不同,但底层可能运作的结果相似,在每次运行时,种子所产生的随机数位置会发生改变,产生不同的值,但是每当重新运行程序时,种子源位置又是相似的,所以地址的变换也是相似的,因此产生的序列是相同的。

import java.util.Random;

public class test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Random ra = new Random(2);
		// Random rb = new Random(System.currentTimeMillis());
		for (int i = 0; i < 20; i++) {
			System.out.println(ra.nextInt(10));
		}

	}
}
结果:
8
2
0
7
9
0
6
9
7
8
4
6
4
4
4
6
7
9
0
1

可以看出将循环次数改为20,前10个随机数和循环次数为10时是相同的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值