0+到10+随机数+java_Java随机数总结
先放⼀道⾯试真题
以下关于随机数的描述,正确的是:
A. Matn.random() 可以⽣成 [ 0 , 1 ] 内的任意⼩数
B. ( 10 ) 可以⽣成 [ 0 , 10 ] 内的任意整数
C. new java.util.Random().nextInt( 11 ) 可以⽣成 [ 0 , 10 ] 内的任意整数
D. new java.util.Math().random() 可以⽣成 [ 0 , 1 ) 内的任意⼩数
在Java项⽬中通常主要是通过Math.random⽅法和Random类来获得随机数的,下⾯将从概述,使⽤技巧,源码分析等⽅⾯进⾏介绍。
⼀、Random类
1.概述
Random类中实现的随机算法是伪随机,也就是有规则的随机,实际上就是⼀个数字(seed)经过运算后近似随机数的数字。所以实际上伪随机是完全可以通过运算预测的。Java中的随机数种⼦若不填写就会使⽤缺省值,即系统时间。
2、Random对象的构造⽅法
a、public Random()
该构造⽅法使⽤⼀个和当前系统时间对应的相对时间有关的数字作为种⼦数,然后使⽤这个种⼦数构造Random对象。
b、public Random(long seed)
该构造⽅法可以通过给定的种⼦进⾏创建。
如下代码所⽰:
public class Client {
public static void main(String[] args) {
Random r = new Random();
Random r1 = new Random(10);
for(int i=1;i<4;i++){
System.out.println("第"+i+"次,r=:"+r.nextInt()+"r1=:"+r1.nextInt());
}
}
}
观察结果发现r1多次运⾏产⽣结果相同,r不同
3.Java.util.Random()类的⽅法
PS:什么是随机数⽣成器序列?类似⼀个数组,⾥⾯存着⽣成好的随机数,详见第三部分源码分析
protected int next(int bits):⽣成下⼀个伪随机数,参数bits应该是位数。
boolean nextBoolean():返回下⼀个伪随机数,它是取⾃此随机数⽣成器序列的均匀分布的boolean值,⽣成true和false的值⼏率相等。
void nextBytes(byte[] bytes):⽣成随机字节并将其置于⽤户提供的 byte 数组中。
double nextDouble():返回下⼀个伪随机数,它是取⾃此随机数⽣成器序列的、在0.0和1.0之间均匀分布的 double值,不包括1.0
float nextFloat():同上,但类型为Float
double nextGaussian():返回下⼀个伪随机数,它是取⾃此随机数⽣成器序列的、呈⾼斯(“正态”)分布的double值,其平均值是0.0标准差是1.0。
int nextInt():返回下⼀个伪随机数,它是此随机数⽣成器的序列中均匀分布的 int 值,该值介于int的区间,也就是-231到231-1之间。
int nextInt(int n):返回⼀个伪随机数,它是取⾃此随机数⽣成器序列的、该值介于[0,n)的区间,也就是0到n,不包括n。
long nextLong():返回下⼀个伪随机数,它是取⾃此随机数⽣成器序列的均匀分布的 long 值。
void setSeed(long seed):使⽤单个 long 种⼦设置此随机数⽣成器的种⼦。
常⽤的⽅法主要是2.4.7.8.10,记住这⼏个即可,下⾯介绍随机数的使⽤技巧。
4.使⽤⽰例
Random r = new Random();
a、⽣成[0,1.0)区间的⼩数
double d1 = r.nextDouble();
直接使⽤nextDouble⽅法获得。
b、⽣成[0,5.0)区间的⼩数
double d2 = r.nextDouble() * 5;
因为nextDouble⽅法⽣成的数字区间是[0,1.0),将该区间扩⼤5倍即是要求的区间。
同理,⽣成[0,d)区间的随机⼩数,d为任意正的⼩数,则只需要将nextDouble⽅法的返回值乘以d即可。
c、⽣成[1,2.5)区间的⼩数
double d3 = r.nextDouble() * 1.5 + 1;
⽣成[1,2.5)区间的随机⼩数,则只需要⾸先⽣成[0,1.5)区间的随机数字,然后将⽣成的随机数区间加1即可。
同理,⽣成任意⾮从0开始的⼩数区间[d1,d2)范围的随机数字(其中d1不等于0),则只需要⾸先⽣成[0,d2-d1)区间的随机数字,然后将⽣成的随机数字区间加上d1即可。
d、⽣成任意整数
int n1 = r.nextInt();
直接使⽤nextInt⽅法即可。
e、⽣成[0,10)区间的整数
n2 = Math.Int() % 10);```
以上两⾏代码均可⽣成[0,10)区间的整数。
第⼀种实现使⽤Random类中的nextInt(int n)⽅法直接实现。
第⼆种实现中,⾸先调⽤nextInt()⽅法⽣成⼀个任意的int数字,该数字和10取余以后⽣成的数字区间为(-10,10),然后再对该区间求绝对值,则得到的区间就是[0,10)了。
同理,⽣成任意[0,n)区间的随机整数,都可以使⽤如下代码:
```int n2 = r.nextInt(n);
n2 = Math.Int() % n);```
>f、⽣成[0,10]区间的整数
int n3 = r.nextInt(11);
n3 = Math.Int() % 11);
相对于整数区间,[0,10]区间和[0,11)区间等价,所以即⽣成[0,11)区间的整数。
>g、⽣成[-3,15)区间的整数
int n4 = r.nextInt(18) - 3;
n4 = Math.Int() % 18) - 3;
⽣成⾮从0开始区间的随机整数,可以参看上⾯⾮从0开始的⼩数区间实现原理的说明。
>h、⼏率实现
按照⼀定的⼏率实现程序逻辑也是随机处理可以解决的⼀个问题。下⾯以⼀个简单的⽰例演⽰如何使⽤随机数字实现⼏率的逻辑。
在前⾯的⽅法介绍中,nextInt(int n)⽅法中⽣成的数字是均匀的,也就是说该区间内部的每个数字⽣成的⼏率是相同的。那么如果⽣成⼀个[0,100)区间的随机整数,则每个数字⽣成的⼏率应该是相同的,⽽且由于该区间中总计有100个整数,所以每个数字的⼏率都是1%。按照这个理论,可以实现程序中的⼏率问题。
⽰例:随机⽣成⼀个整数,该整数以55%的⼏率⽣成1,以40%的⼏率⽣成2,以5%的⼏率⽣成3。实现的代码如下:
int n5 = r.nextInt(100);
int m; //结果数字
if(n5 < 55){ //55个数字的区间,55%的⼏率
m = 1;
}else if(n5 < 95){//[55,95),40个数字的区间,40%的⼏率
m = 2;
}else{
m = 3;
}```
因为每个数字的⼏率都是1%,则任意55个数字的区间的⼏率就是55%,为了代码⽅便书写,这⾥使⽤[0,55)区间的所有整数,后续的原理⼀样。
当然,这⾥的代码可以简化,因为⼏率都是5%的倍数,所以只要以5%为基础来控制⼏率即可,下⾯是简化的代码实现:
int n6 = r.nextInt(20);
int m1;
if(n6 < 11){
m1 = 1;
}else if(n6 < 19){
m1= 2;
}else{
m1 = 3;
}
在程序内部,⼏率的逻辑就可以按照上⾯的说明进⾏实现。
##⼆、java.lang.Math.Random⽅法
###1.使⽤
调⽤这个Math.Random()函数能够返回带正号的double值,该值⼤于等于0.0且⼩于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是⼀个伪随机选择的数,在该范围内(近似)均匀分布。
例如下⾯的实验代码
编译通过后运⾏结果如下图
观察会发现代码的⽤⼀个循环10次循环输出num的取值,均随机分布在[0,3)之间!在使⽤Math.Random()的时候需要注意的地⽅时该函数是返回double类型的值,所以在要赋值给其他类型的变量的时候注意需要进⾏塑形转换。
###2.总结
a.通过阅读Math类的源代码可以发现,Math类中的random⽅法就是直接调⽤Random类中的nextDouble⽅法实现的,两者并⽆差别。
只是random⽅法的调⽤⽐较简单,所以很多程序员都习惯使⽤Math类的random⽅法来⽣成随机数字。
java生成随机数的方法
b.java.util.Random()在调⽤的时候可以实现和java.Math.Random()⼀样的功能,⽽且他具有很多的调⽤⽅法,相对来说⽐较灵活。所以从总体来看,使⽤java.util.Random()会相对来说⽐较灵活⼀些。
C.java.Math.Random()实际是在内部调⽤java.util.Random()的,它有⼀个致命的弱点,它和系统时间有关,也就是说相隔时间很短的两个random⽐如:
double a = Math.random();
double b = Math.random();
即有可能会得到两个⼀模⼀样的double。
d。在使⽤random类时,如果想避免出现随机数字相同的情况,则需要注意,⽆论项⽬中需要⽣成多少个随机数字,都只使⽤⼀个Random对象即可。
##三、源码分析
其实我也没有看太懂……先把这个博客上的内容贴过来,等弄懂了再补⾃⼰的解释吧……
来⾃
* @param seed the initial seed
* @see #setSeed(long)
*/
++++++++++++++++++带种⼦数的构造⽅法+++++++++++++
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}
++++++++++++++netInt⽅法带参数的那个源码++++++++++++ * @since 1.2
*/
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
可见Random的种⼦要求 ⼤于0 的 。。。
+++++++++++++++nextDouble⽅法实现+++++++++++
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27))
/ (double)(1L << 53);
}
+++++++++++++++nextFloat⽅法实现+++++++++++++
public float nextFloat() {
return next(24) / ((float)(1 << 24));
}
+++++++++++++++++nextInt⽅法实现:++++++++++
public int nextInt() {
return next(32);
}
可见所有的随机数产⽣都和⼀个叫 next⽅法有关,这个⽅法是这样的:* @since 1.1
*/
protected int next(int bits) {
long oldseed, nextseed;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论