Java中常用的三种产生随机数的方法详解(currentTimeMills,random,Math.random)

Java中常用的三种产生随机数的方法及其原理详解(currentTimeMills,random,Math.random)


这学期笔者开始学习Java,由于以前有了C做基础,学Java明显可以轻松许多,但是这几天有个问题很苦恼,有几道题目要产生随机数,我百度了一下,发现了多种使用的方法,但大多知识是零星的。于是今天我打算给大家分享一下我总结了的三种在Java里面很常用的方法。如果有任何不恰当的地方,欢迎大家在评论区不吝指出或者是私信我,我会尽力改正,给大家呈现更优质的内容。

一.使用currentTimeMills

currentTimeMills返回的是从1970年一月一日零时零分零秒到现在总共的毫秒数,我们可以用这个毫秒数来产生随机数。如何产生呢?

如果要是产生[0,n-1]范围内的随机数,可以这样写:

int randomNum1 = (int)(System.currentTimeMillis()%10);
//用当前时间获得[0,9]之间的随机数

这个函数就能够产生[0,9]范围内的随机数啦!
那我们要是想产生多个随机数怎么办,有的小伙伴可能会想,我写两个不就好了,那我们看看写两个到底行不行:

 int randomNum1 = (int)System.currentTimeMillis()%10;
 //用当前时间获得[0,9]之间的随机数
  int randomNum2 = (int)System.currentTimeMillis()%10;
   System.out.println("用当前时间获得的随机数:"+randomNum1+" "+randomNum2);
  //输出第一次:用当前时间获得的随机数:-1 -1
  //输出第二次:用当前时间获得的随机数:-1 -1
  //输出第三次:用当前时间获得的随机数:-9 -9

我把程序运行了三次,但是奇怪的是,程序并没有按照我们所想的那样输出,这是为什么呢?细心地小伙伴可能发现了,上面第一个代码块和第二个代码块有一点细微的差别,第一个代码块System.currentTimeMillis()%10整体打上了括号,而第二个没有,出现这个问题的原因我细细说来。

最最重要的一点,我们把随机数定义成了int型,而System.currentTimeMillis返回的是一个long型的毫秒数,所以我用了强制类型转换(int)要知道,强制类型转换()可是优先级很高的,*,%的优先级都比它低,所以如果不打括号,系统就会把一个long型的值强制转换为int型,因为这个long型的数据的值太大了,以至于超过了int的范围,这个过程中当然会出错了,口说无凭,上代码:

  int randomNum1 = (int)(System.currentTimeMillis()%10);
  //用当前时间获得[0,9]之间的随机数
  int randomNum2 = (int)System.currentTimeMillis()%10;
  long randomNum3 = System.currentTimeMillis();
  int randomNum4 = (int)System.currentTimeMillis();
  System.out.println("打括号:"+randomNum1+"\n不打括号"
  +randomNum2+"\n函数返回值"+randomNum3+"\n强制转换后得值"+randomNum4);
  /*
  打括号:1
  不打括号-3
  函数返回值1582714328081
  强制转换后得值-2128604143
  
  打括号:8
  不打括号-6
  函数返回值1582714367538
  强制转换后得值-2128564686
  
  打括号:3
  不打括号-1
  函数返回值1582714395723
  强制转换后得值-2128536501
  */

上面我三次运行了程序,相信小伙伴们应该知道错误的原因了吧!int的取值是在-2147483648~2147483647之间,显然这个返回的毫秒值完全超过了它的范围!于是我把代码改成这样:

 int randomNum1 = (int)(System.currentTimeMillis()%10);
 //用当前时间获得[0,9]之间的随机数
  int randomNum2 = (int)(System.currentTimeMillis()%10);
  //long randomNum3 = System.currentTimeMillis();
  //int randomNum4 = (int)System.currentTimeMillis();
  System.out.println("用当前时间获得[0,9]之间的随机数:"+randomNum1+" "+randomNum2);
  //用当前时间获得[0,9]之间的随机数:5 5
  //用当前时间获得[0,9]之间的随机数:7 7
  //用当前时间获得[0,9]之间的随机数:8 8

上面的程序同样运行了三次,又出现了奇奇怪怪的效果,我本来是想产生两个随机数,但是这两个随机数怎么老是一样啊!

当我们分析产生随机数的原理之后,很容易想到,因为是对时间进行运算,程序运行所需要的时间是很快的,两条间隔的语句获得时间的返回值相差的时间不到一毫秒,这样就导致了产生的随机数相同,只要把其中一个做一点改动就行,比如把返回值乘以一个数之后再取模,这样就能避免这种情况,上代码:

  int randomNum1 = (int)(System.currentTimeMillis()%10);
  int randomNum2 = (int)(System.currentTimeMillis()*3%10);
  //long randomNum3 = System.currentTimeMillis();
  //int randomNum4 = (int)System.currentTimeMillis();
  System.out.println("用当前时间获得[0,9]之间的随机数:"+randomNum1+" "+randomNum2);
  //用当前时间获得[0,9]之间的随机数:4 2
  //用当前时间获得[0,9]之间的随机数:1 3
  //用当前时间获得[0,9]之间的随机数:6 8

这样问题就能很好的解决了,至于怎么产生[a.b],范围内的随机数,让我们用数学来算:
(int)(System.currentTimeMillis()%n
原来的范围:[0,n-1] 两边同时加m
(int)(System.currentTimeMillis()%n+m
变化后的范围:[m,m+n-1]
解方程组:a=m; b=m+n-1;

可以知道产生[a,b]范围内的随机数,用(int)(System.currentTimeMillis()%n+m;其中m=a;n=b-a+1;

第一个终于分享完了
在这里插入图片描述

二.使用random

用法如下,直接砸代码:

 Random random = new Random();
 int a = random.nextInt(10);//产生[0,9]的随机数
 int b = random.nextInt(10);
 int c = random.nextInt(10);
 System.out.println("用产生种子的方法获得的随机数:"+a+" "+b+" "+c);
 //用产生种子的方法获得的随机数:1 0 4
 //用产生种子的方法获得的随机数:5 4 4
 //用产生种子的方法获得的随机数:0 5 1

照样,也运行了三次,产生的结果还是蛮好的,我们来解释一下
Random random = new Random();
这一句的作用是产生种子值()里面是可以带数字的,里面的数字就是种子值
如果不带数字的话,那么种子值默认为当前时间的毫秒数
int a = random.nextInt(10);
这一句括号里面的10,意思是产生[0,9]范围内的随机数

上面的程序演示的是不带种子值,那么我们要是带上种子值呢?看代码:

     Random random = new Random(1);
     int a = random.nextInt(10);//产生[0,9]的随机数
     int b = random.nextInt(10);
     int c = random.nextInt(10);
     System.out.println("种子值为1获得的随机数:"+a+" "+b+" "+c);
     //种子值为1获得的随机数:5 8 7
     //种子值为1获得的随机数:5 8 7
     //种子值为1获得的随机数:5 8 7
     Random random = new Random(2);
     int a = random.nextInt(10);//产生[0,9]的随机数
     int b = random.nextInt(10);
     int c = random.nextInt(10);
     System.out.println("种子值为2获得的随机数:"+a+" "+b+" "+c);
     //种子值为2获得的随机数:8 2 0
     //种子值为2获得的随机数:8 2 0
     //种子值为2获得的随机数:8 2 0
     Random random = new Random(2002);
     int a = random.nextInt(10);//产生[0,9]的随机数
     int b = random.nextInt(10);
     int c = random.nextInt(10);
     System.out.println("种子值为2002获得的随机数:"+a+" "+b+" "+c);
     //种子值为2002获得的随机数:8 3 7
     //种子值为2002获得的随机数:8 3 7
     //种子值为2002获得的随机数:8 3 7

三次改变种子值,每次输出三次,每个种子值得到的结果相同,这是因为一旦确定了种子值,在范围内的随机数其实就已经指定了,如果要生成多个或者是多次随机数,最好还是不要指定种子值。

下面要看看怎么产生[a,b]范围内的随机数,照样,我们来解方程:
int a = random.nextInt(n);
原来的范围:[0,n-1] 两边同时加m
int a = random.nextInt(n)+m;
变化后的范围:[m,m+n-1]
解方程组:a=m; b=m+n-1;

可以知道产生[a,b]范围内的随机数,用int a = random.nextInt(n)+m;其中m=a;n=b-a+1;这个范围的计算和第一种方法是一样的!

三.使用Math.random()

Math.random()返回一个double类型的随机数d,其中d的范围为[0,1)
这个函数是这样使用的:

     int d = (int)(9 *Math.random())+1;
     //产生[1,10)的整数
     int e = (int)(9 *Math.random())+1;
     System.out.println("用Math.random获得的随机数:"+d+" "+e);
     //用Math.random获得的随机数:2 8
     //用Math.random获得的随机数:4 6
     //用Math.random获得的随机数:2 6

照样运行了三次,下面来解释一下:
int d = (int)(9 *Math.random())+1;
把得到的double类型的数强制转换为int型的数并赋值给int型的变量
至于为什么范围是得到的产生[1,10)的整数的整数,老规矩

数学代换走起
在这里插入图片描述

int d = (int)((y-x)*Math.random())+x;
[0,1.0) 同乘y-x
[0,y-x) 两边+x
[x,y)

这样第三个产生随机数的问题我们也解决啦!!!
在这里插入图片描述
最后,给大家看看这三种方式放在一起:

public class Test_fot_CSDN {
 public static void main(String[] args){
  int randomNum1 = (int)(System.currentTimeMillis()%10);
  int randomNum2 = (int)(System.currentTimeMillis()*3%10);
  //long randomNum3 = System.currentTimeMillis();
  //int randomNum4 = (int)System.currentTimeMillis();
  System.out.println("用当前时间获得[0,9]之间的随机数:"+randomNum1+" "+randomNum2);
     Random random = new Random(2002);
     int a = random.nextInt(10);//产生[0,9]的随机数
     int b = random.nextInt(10);
     int c = random.nextInt(10);
     System.out.println("用产生种子的方法获得的随机数:"+a+" "+b+" "+c);
     int d = (int)(9 *Math.random())+1;//产生[1,10)的整数
     int e = (int)(9 *Math.random())+1;
     System.out.println("用Math.random获得的随机数:"+d+" "+e);  
     }
 }
 /*
用当前时间获得[0,9]之间的随机数:8 4
用产生种子的方法获得的随机数:8 3 7
用Math.random获得的随机数:6 7
*/

那么,这次的分享就到这啦,希望各位看到我的文章能更加优秀,小伙伴们有什么好的想法,欢迎一起交流哦!

原创不易
在这里插入图片描述
下次见!

发布了3 篇原创文章 · 获赞 68 · 访问量 2318

猜你喜欢

转载自blog.csdn.net/ztlzlzl/article/details/104521962