Java 生成随机数

本文介绍了Java中生成随机数的两种方式:Math.random()和Random类。Math.random()生成[0,1)区间的小数,Random类则提供更丰富的功能,如生成指定区间的整数、浮点数。相同种子的Random对象会生成相同序列的随机数,而无种子的Random实例每次运行结果不同。此外,文章还探讨了如何生成指定范围内的随机数及其应用。" 132705000,19687573,使用boost::fusion::flatten_view扁平化元组,"['C++', 'Boost库', '元组处理', '编程技巧']

Java 生成随机数

随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串、数字。或者随即生成一个不定长度的数字、或者进行一个模拟的随机选择等等。Java提供了最基本的工具,可以实现生成伪随机数。

Java 中主要有两种生成随机数的方式:

  • 利用 Math 类中的 random() 方法。
  • 利用 Random 类。

Math.random()

随机生成 0≤x&lt;10 \leq x &lt; 10x<1 的小数,即在 [0,1)[0,1)[0,1) 之间取值。

应用
随机生成 m∼nm \sim nmn 之间的整数,包括 m 和 n 。
公式: (int)((Math.random()∗(n−m+1))+1)(int)((Math.random()\ast(n-m+1))+1)(int)((Math.random()(nm+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}-12312311 之间。

  • 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}-12632631 之间。

  • 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 之间的整数

总结

  1. 随机数很常用,在Java有三种产生方式,以Random随机数的使用最为复杂。
  2. Random类对象有是否带种子之分,带种子的只要种子相同,多次运行,生成随机数的结果总是相同。
  3. 带种子随机数的带种子的对象创建方式有两种,效果一样。
  4. Random 的功能涵盖了 Math.random() 的功能。
  5. 可以通过随机数去做实现随机字符串等复杂的随机数据。
  6. 不重复的随机数实际意义不大。

在 Java 中可以使用 Random 类产生一个随机数发生器。它有两种形式的构造函数,分别是 Random() 和 Random(long seed) 。

  • Random() 使用当前时间即 System.currentTimeMillis() 作为发生器的种子。
  • Random(long seed) 使用指定的 seed 作为发生器的种子。

随机数发生器(Random)对象产生以后,通过调用不同的方法:nextInt() 、nextLong() 、nextFloat() 、nextDouble() 等获得不同类型随机数。

  1. 生成随机数
    如果两个 Random 对象使用相同的种子,并且以相同的顺序调用相同的函数,那它们返回值完全相同。
  2. 指定范围内的随机数
    随机数控制在某个范围内,使用模数运算符 % 实现。获得的随机数有正有负的,用Math.abs使获取数据范围为非负数。
  3. 获取指定范围内的不重复随机数

Java中的随机数是否可以重复?Java中产生的随机数能否可以用来产生数据库主键?

  1. 使用不带参数的 Random() 构造函数
    使用不带参数的 Random() 构造函数产生的随机数不会重复。
  2. 为 Random 设置种子数
    无论程序运行多少次,其结果总是相同的。甚至在不同的机器上测试,结果也不会改变。

原因分析:

  1. Random 类的实例用于生成伪随机数流,此类使用 48 位的种子,该种子可以使用线性同余公式对其进行修改。如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列。为了保证实现这种特性,我们为类Random指定了特定的算法。为了 Java 代码的完全可移植性,Java 实现必须让类 Random 使用此处所示的所有算法。但是允许 Random 类的子类使用其他算法,只要其符合所有方法的常规协定即可。
  2. 如果没有提供种子数,Random实例的种子数将是当前时间的毫秒数,可以通过System.currentTimeMillis()来获得当前时间的毫秒数。
public Random() {
    this(System.currentTimeMillis()); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值