Java 生成随机数
随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串、数字。或者随即生成一个不定长度的数字、或者进行一个模拟的随机选择等等。Java提供了最基本的工具,可以实现生成伪随机数。
Java 中主要有两种生成随机数的方式:
- 利用 Math 类中的 random() 方法。
- 利用 Random 类。
Math.random()
随机生成 0≤x<10 \leq x < 10≤x<1 的小数,即在 [0,1)[0,1)[0,1) 之间取值。
应用
随机生成 m∼nm \sim nm∼n 之间的整数,包括 m 和 n 。
公式: (int)((Math.random()∗(n−m+1))+1)(int)((Math.random()\ast(n-m+1))+1)(int)((Math.random()∗(n−m+1))+1)
/*
* 随机生成 m ~ n 之间的整数。
* m = 10, n = 20
* (int) (Math.random() * (20 - 10 + 1) + 10) = (int) (Math.random() * 11 + 10)
*/
int m = 10, n = 20, x = 0;
for (int i = m; i <= n; i++) {
do {
x = (int) (Math.random() * (n - m + 1) + m);
System.out.print(x + " ");
} while (x != i);
System.out.println();
}
【结果】
13 14 12 20 18 17 19 20 19 12 14 17 16 13 15 20 11 14 16 11 10
18 20 15 15 17 19 14 12 17 16 18 17 20 14 11
17 20 12
13
19 13 19 15 17 11 14
10 11 12 10 18 16 18 19 19 20 16 14 17 19 16 10 12 20 18 13 10 15
11 13 11 13 16
11 19 13 10 12 13 13 14 16 11 20 18 18 15 14 11 12 13 17
15 20 13 20 16 12 13 11 10 16 13 11 20 18
17 19
18 10 13 16 11 20
Math.random() 本身是用 Random 类实现的。
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble(); // 返回一个伪随机数,在 0.0 到 1.0 之间均匀分布的 double 值。
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
Random 类
构造方法
- 默认构造方法:
Random random = new Random() - 指定种子数字:
Random random = new Random(see)
等价于Random random = new Random()+random.setSeed(seed)
在进行随机时,随机算法的起源数字称为种子数 (seed) ,在种子数的基础上进行一定的变换,从而产生需要的随机数字。
相同种子数的 Random 对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的 Random 对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。
Random 类两种构造方法的差别:
- 不带种子。此种方式将会返回随机的数字,每次运行结果不一样
- 带种子。此种方式,无论程序运行多少次,返回结果都是一样的
两种方式的差别
- Random类的说明:此类的实例用于生成伪随机数流,此类使用 48 位的种子,该种子可以使用线性同余公式对其进行修改。如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列。为了保证实现这种特性,我们为类 Random 指定了特定的算法。为了 Java 代码的完全可移植性,Java 实现必须让类 Random 使用此处所示的所有算法。但是允许 Random 类的子类使用其他算法,只要其符合所有方法的常规协定即可。
- 如果没有提供种子数,Random 实例的种子数将是当前时间的毫秒数,可以通过 System.currentTimeMillis() 来获得当前时间的毫秒数。
public Random() {
this(System.currentTimeMillis());
}
public Random(long seed);
Random 类中的常用方法
Random 类中的方法比较简单,每个方法的功能也很容易理解。需要说明的是,Random 类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。
-
public void setSeed(long seed)
该方法的作用是重新设置 Random 对象中的种子数。设置完种子数以后的 Random 对象和相同种子数使用 new 关键字创建出的 Random 对象相同。 -
public boolean nextBoolean()
该方法的作用是生成一个随机的 boolean 值,生成 true 和 false 的值几率相等,各有 50% 的几率。 -
public int nextInt()
该方法的作用是生成一个随机的 int 值,该值介于 int 的区间,也就是 −231∼−231−1-2^{31}\sim-2^{31}-1−231∼−231−1 之间。 -
public int nextInt(int n)
该方法的作用是生成一个随机的 int 值,该值介于 [0,n) 的区间,也就是 0 到 n 之间的随机 int 值,包含 0 而不包含 n 。 -
public int nextLong()
该方法的作用是生成一个随机的 long 值,该值介于 long 的区间,也就是 −263∼−263−1-2^{63} \sim -2^{63}-1−263∼−263−1 之间。 -
public double nextFloat()
该方法的作用是生成一个随机的 Floa 值,数值介于 [ 0.0 , 1.0 ) 之间,也就是 0 到 1 之间的随机小数,包含 0.0 而不包含 1.0 。 -
public double nextDouble()
该方法的作用是生成一个随机的 double 值,数值介于 [ 0.0 , 1.0 ) 之间,也就是 0 到 1 之间的随机小数,包含 0.0 而不包含 1.0 。 -
public double nextGaussian()
该方法的作用是生成一个随机的 double 值,其规律服从平均值为 0.0 ,标准偏差为 1.0 的高斯 (“正”) 分布。
Random 类的部分函数:
public class Random {
public Random(); // 创建一个新的随机数生成器。
public Random(long seed); // 使用单个 long 种子创建一个新的随机数生成器。
synchronized public void setSeed(long seed); // 使用单个 long种子设置此随机数生成器的种子。
public void nextBytes(byte[] bytes) ; // 生成随机字节并将它们放入用户提供的字节数组中。
protected int next(int bits); // 生成下一个伪随机数。
public boolean nextBoolean(); // 从该随机数生成器的序列返回下一个伪随机数,均匀分布的 boolean 值。
public int nextInt(); // 从这个随机数生成器的序列返回下一个伪随机数,均匀分布的 int 值。
public int nextInt(int bound); // 从该随机数发生器的序列返回下一个伪随机数,均匀分布介于 0 (含) 和指定值 (不包括) 的 int 值。
public long nextLong(); // 从该随机数发生器的序列返回下一个伪随机数,均匀分布的 long 值。
public float nextFloat(); // 从该随机数生成器的序列返回下一个伪随机数,在 0.0 到 1.0 之间均匀分布的 float 值。
public double nextDouble(); // 从该随机数生成器的序列返回下一个伪随机数,在 0.0 到 1.0 之间均匀分布的 double 值。
public boolean nextGaussian(); // 从该随机数发生器的序列返回下一个伪随机数,服从平均值为 0.0 ,标准偏差为 1.0 的高斯 ("正") 分布的 double 值。
}
应用
使用Random类,一般是生成指定区间的随机数字。使用 Random 类的对象 random 生成随机数:Random random = new Random();
-
生成任意整数
直接使用nextInt方法即可:int num = random.nextInt(); -
生成 [ 0 , n ) 区间的整数
int num = random.nextInt(n);
int num = Math.abs(random.nextInt() % n);
以上两行代码均可生成 [ 0 , n ) 区间的整数。
第一种实现使用 Random 类中的 nextInt(int n) 方法直接实现。
第二种实现中,首先调用 nextInt() 方法生成一个任意的 int 数字,该数字和 n 取余以后生成的数字区间为( -n , n ),对该区间求绝对值,得到 [ 0 , n ) 。 -
生成 [ 0 , n ] 区间的整数
int num = random.nextInt(n + 1);
int num = Math.abs(random.nextInt() % (n + 1));
对于整数区间,[ 0 , n ] 区间和 [ 0 , n+1 ) 区间等价. -
生成 [ n1 , n2 ) 区间的整数
int num = random.nextInt() * (n2 - n1) + n1
int num = Math.abs(random.nextInt() % (n2 - n1)) + n1;
n1 和 n2 可以是负数。 -
生成 [ n1 , n2 ] 区间的整数
int num = random.nextInt() * (n2 - n1 + 1) + n1
int num = Math.abs(random.nextInt() % (n2 - n1 + 1)) + n1;
n1 和 n2 可以是负数。 -
生成 [ n1 , n2 ) 区间的小数
直接使用 nextDouble 方法获得:double num = random.nextDouble() * (n2 - n1) + n1;
也可以使用 nextFloat 方法获得,n1 和 n2 可以是负数。
拓展
利用 System.currentTimeMillis() 产生一个 long 数字,对某数取模可以得到某个范围内的随机数。
long x = System.currentTimeMillis();
int num = (int) (x % n); // 随机生成 0 ~ n-1 之间的整数
总结
- 随机数很常用,在Java有三种产生方式,以Random随机数的使用最为复杂。
- Random类对象有是否带种子之分,带种子的只要种子相同,多次运行,生成随机数的结果总是相同。
- 带种子随机数的带种子的对象创建方式有两种,效果一样。
- Random 的功能涵盖了 Math.random() 的功能。
- 可以通过随机数去做实现随机字符串等复杂的随机数据。
- 不重复的随机数实际意义不大。
在 Java 中可以使用 Random 类产生一个随机数发生器。它有两种形式的构造函数,分别是 Random() 和 Random(long seed) 。
- Random() 使用当前时间即 System.currentTimeMillis() 作为发生器的种子。
- Random(long seed) 使用指定的 seed 作为发生器的种子。
随机数发生器(Random)对象产生以后,通过调用不同的方法:nextInt() 、nextLong() 、nextFloat() 、nextDouble() 等获得不同类型随机数。
- 生成随机数
如果两个 Random 对象使用相同的种子,并且以相同的顺序调用相同的函数,那它们返回值完全相同。 - 指定范围内的随机数
随机数控制在某个范围内,使用模数运算符 % 实现。获得的随机数有正有负的,用Math.abs使获取数据范围为非负数。 - 获取指定范围内的不重复随机数
Java中的随机数是否可以重复?Java中产生的随机数能否可以用来产生数据库主键?
- 使用不带参数的 Random() 构造函数
使用不带参数的 Random() 构造函数产生的随机数不会重复。 - 为 Random 设置种子数
无论程序运行多少次,其结果总是相同的。甚至在不同的机器上测试,结果也不会改变。
原因分析:
- Random 类的实例用于生成伪随机数流,此类使用 48 位的种子,该种子可以使用线性同余公式对其进行修改。如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列。为了保证实现这种特性,我们为类Random指定了特定的算法。为了 Java 代码的完全可移植性,Java 实现必须让类 Random 使用此处所示的所有算法。但是允许 Random 类的子类使用其他算法,只要其符合所有方法的常规协定即可。
- 如果没有提供种子数,Random实例的种子数将是当前时间的毫秒数,可以通过System.currentTimeMillis()来获得当前时间的毫秒数。
public Random() {
this(System.currentTimeMillis());
}
本文介绍了Java中生成随机数的两种方式:Math.random()和Random类。Math.random()生成[0,1)区间的小数,Random类则提供更丰富的功能,如生成指定区间的整数、浮点数。相同种子的Random对象会生成相同序列的随机数,而无种子的Random实例每次运行结果不同。此外,文章还探讨了如何生成指定范围内的随机数及其应用。"
132705000,19687573,使用boost::fusion::flatten_view扁平化元组,"['C++', 'Boost库', '元组处理', '编程技巧']

7408

被折叠的 条评论
为什么被折叠?



