java生成m到n的随机数

知兮丶青
阅读(1763) 2017-12-17
java生成m到n的随机数
java生成m到n的随机数

java怎么生成m至n的随机数,java提供2种简便生成随机数的方式。


第一种:是java.lang.Math类的Math.Random(),其实底层也是new Random()后面再介绍;

第二种:是java.util.Random类,Random random = new Random();


函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间。

返回值是一个伪随机选择的数(近似)均匀分布的范围。



实例代码

生成[0-1)的方法,范围0<=r<1,大于等于0且小于1

double r = Math.random();
System.out.println(r);


生成[0,n)的方法,范围0<=r<n,大于等于0且小于n

Random rand = new Random();
int r = rand.nextInt(n);
System.out.println(r);


生成[0,n]的方法,范围0<=r<=n,大于等于0且小于等于n

int r = (int)Math.round(Math.random() * n);
System.out.println(r);


生成[m,n]的方法,范围m<=r<=n,大于等于m且小于等于n

int r = (int)Math.round(Math.random()*(n-m) + m);
System.out.println(r);



解释

Math.Random(),其实底层也是调用Random random = new Random();的,来看看底层源码片段:

/**
 * 返回一个带正号的{@code double}值,更大
 * 大于或等于{@code 0.0},小于{@code 1.0}。
 * 返回值的选择(近似)均匀分布的范围。
 *
 * 当这个方法被首次调用时,它会创建一个新的
 * 伪数字生成器,就像通过表达式一样
 *
 * {@code新java.util.Random()}
 * 之后使用这个新的伪数字生成器
 * 所有对该方法的调用,并无其他用途。
 *
 * 此方法正确同步,允许正确使用
 * 不止一个线程。但是,如果许多线程需要生成
 * 伪随机数以较大的速度,可以减少争用
 * 每个线程都有自己的伪数字生成器。
 * @返回一个大于或等于的伪随机{@code double}
 * 对{@code 0.0}和小于{@code 1.0}。
 * @see随机# nextDouble()
 */
public static double random() {
    Random rnd = randomNumberGenerator;
    if (rnd == null) rnd = initRNG();
    return rnd.nextDouble();
}
private static Random randomNumberGenerator;
private static synchronized Random initRNG() {
    Random rnd = randomNumberGenerator;
    return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
}

可以看出,当randomNumberGenerator是静态变量,如果为空,测创建一个新的Random赋值给randomNumberGenerator。


再看看Random的构造函数,使用一个seedUniquifier() ^ System.nanoTime()返回值作为种子数。构造唯一标识种子。

/**
 * 创建一个新的随机数生成器。这个构造函数集
 * 随机数产生器的种子极有可能
 * 与此构造函数的任何其他调用不同。
 */
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
    // L'Ecuyer, "Tables of Linear Congruential Generators of
    // Different Sizes and Good Lattice Structure", 1999
    for (;;) {
        long current = seedUniquifier.get();
        long next = current * 181783497276652981L;
        if (seedUniquifier.compareAndSet(current, next))
            return next;
    }
}


什么是种子:使用一个{@code long}种子创建一个新的随机数生成器,种子是伪随机的内部状态的初始值。种子还可以通过setSeed设置:

Random rand = new Random();
long code = 100;
rand.setSeed(code);



探究

种子相同情况

Random rand1 = new Random(100);
Random rand2 = new Random(100);
for(int i=0;i<10;i++) {
    System.out.print(rand1.nextInt(10));
    System.out.print(" ");
    System.out.print(rand2.nextInt(10));
    System.out.println();
}
5 5
0 0
4 4
8 8
1 1
6 6
6 6
8 8
3 3
3 3

种子相同,就算实例也不同,不管运行多少次,打印出的随机数都是相同的。输出相同,如果知道种子值,能猜测下一位随机数。


种子不同情况

Random rand1 = new Random();
Random rand2 = new Random();
for(int i=0;i<10;i++) {
    System.out.print(rand1.nextInt(10));
    System.out.print(" ");
    System.out.print(rand2.nextInt(10));
    System.out.println();
}
5 4
1 6
2 3
3 8
7 6
9 6
1 9
8 9
0 5
0 0

种子不同,不管实例相不相同,都不会生成相同的随机数。



总结

1. 同一个种子,生成N个随机数,当你设定种子的时候,这N个随机数是什么已经确定。相同次数生成的随机数字是完全相同的。(例1)

2. 如果用相同的种子创建两个Random实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数字序列。(例1)

3. Java的随机数都是通过算法实现的,Math.random()底层是调用Random()类,实例唯一。 

4. 使用java.util.Random()会相对来说比较灵活一些,可以产生正态、高斯、均匀分布的随机数。



应用实例

附带个实例

题目:求10个-100到100的随机数绝对值的最新小值是多少?

int m = -100;
int n = 100;
Set<Integer> nums = new HashSet<Integer>();
for(int i=0;i<10;i++) {
    int r = (int)Math.round(Math.random()*(n-m) + m);
    System.out.println(r);
    nums.add(Math.abs(r));
}
int min = Collections.min(nums);
System.out.println("10个 -100到100的随机数 绝对值 的最小值是:"+min);


原创文章,转载请注明出处:https://www.weizhixi.com/article/34.html