0+到10+随机数+java_Java随机数总结
先放一道面試真題
以下關(guān)于隨機(jī)數(shù)的描述,正確的是:
A. Matn.random() 可以生成 [ 0 , 1 ] 內(nèi)的任意小數(shù)
B. Random.next( 10 ) 可以生成 [ 0 , 10 ] 內(nèi)的任意整數(shù)
C. new java.util.Random().nextInt( 11 ) 可以生成 [ 0 , 10 ] 內(nèi)的任意整數(shù)
D. new java.util.Math().random() 可以生成 [ 0 , 1 ) 內(nèi)的任意小數(shù)
在Java項(xiàng)目中通常主要是通過(guò)Math.random方法和Random類(lèi)來(lái)獲得隨機(jī)數(shù)的,下面將從概述,使用技巧,源碼分析等方面進(jìn)行介紹。
一、Random類(lèi)
1.概述
Random類(lèi)中實(shí)現(xiàn)的隨機(jī)算法是偽隨機(jī),也就是有規(guī)則的隨機(jī),實(shí)際上就是一個(gè)數(shù)字(seed)經(jīng)過(guò)運(yùn)算后近似隨機(jī)數(shù)的數(shù)字。所以實(shí)際上偽隨機(jī)是完全可以通過(guò)運(yùn)算預(yù)測(cè)的。Java中的隨機(jī)數(shù)種子若不填寫(xiě)就會(huì)使用缺省值,即系統(tǒng)時(shí)間。
2、Random對(duì)象的構(gòu)造方法
a、public Random()
該構(gòu)造方法使用一個(gè)和當(dāng)前系統(tǒng)時(shí)間對(duì)應(yīng)的相對(duì)時(shí)間有關(guān)的數(shù)字作為種子數(shù),然后使用這個(gè)種子數(shù)構(gòu)造Random對(duì)象。
b、public Random(long seed)
該構(gòu)造方法可以通過(guò)給定的種子進(jìn)行創(chuàng)建。
如下代碼所示:
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());
}
}
}
觀察結(jié)果發(fā)現(xiàn)r1多次運(yùn)行產(chǎn)生結(jié)果相同,r不同
3.Java.util.Random()類(lèi)的方法
PS:什么是隨機(jī)數(shù)生成器序列?類(lèi)似一個(gè)數(shù)組,里面存著生成好的隨機(jī)數(shù),詳見(jiàn)第三部分源碼分析
protected int next(int bits):生成下一個(gè)偽隨機(jī)數(shù),參數(shù)bits應(yīng)該是位數(shù)。
boolean nextBoolean():返回下一個(gè)偽隨機(jī)數(shù),它是取自此隨機(jī)數(shù)生成器序列的均勻分布的boolean值,生成true和false的值幾率相等。
void nextBytes(byte[] bytes):生成隨機(jī)字節(jié)并將其置于用戶(hù)提供的 byte 數(shù)組中。
double nextDouble():返回下一個(gè)偽隨機(jī)數(shù),它是取自此隨機(jī)數(shù)生成器序列的、在0.0和1.0之間均勻分布的 double值,不包括1.0
float nextFloat():同上,但類(lèi)型為Float
double nextGaussian():返回下一個(gè)偽隨機(jī)數(shù),它是取自此隨機(jī)數(shù)生成器序列的、呈高斯(“正態(tài)”)分布的double值,其平均值是0.0標(biāo)準(zhǔn)差是1.0。
int nextInt():返回下一個(gè)偽隨機(jī)數(shù),它是此隨機(jī)數(shù)生成器的序列中均勻分布的 int 值,該值介于int的區(qū)間,也就是-231到231-1之間。
int nextInt(int n):返回一個(gè)偽隨機(jī)數(shù),它是取自此隨機(jī)數(shù)生成器序列的、該值介于[0,n)的區(qū)間,也就是0到n,不包括n。
long nextLong():返回下一個(gè)偽隨機(jī)數(shù),它是取自此隨機(jī)數(shù)生成器序列的均勻分布的 long 值。
void setSeed(long seed):使用單個(gè) long 種子設(shè)置此隨機(jī)數(shù)生成器的種子。
常用的方法主要是2.4.7.8.10,記住這幾個(gè)即可,下面介紹隨機(jī)數(shù)的使用技巧。
4.使用示例
Random r = new Random();
a、生成[0,1.0)區(qū)間的小數(shù)
double d1 = r.nextDouble();
直接使用nextDouble方法獲得。
b、生成[0,5.0)區(qū)間的小數(shù)
double d2 = r.nextDouble() * 5;
因?yàn)閚extDouble方法生成的數(shù)字區(qū)間是[0,1.0),將該區(qū)間擴(kuò)大5倍即是要求的區(qū)間。
同理,生成[0,d)區(qū)間的隨機(jī)小數(shù),d為任意正的小數(shù),則只需要將nextDouble方法的返回值乘以d即可。
c、生成[1,2.5)區(qū)間的小數(shù)
double d3 = r.nextDouble() * 1.5 + 1;
生成[1,2.5)區(qū)間的隨機(jī)小數(shù),則只需要首先生成[0,1.5)區(qū)間的隨機(jī)數(shù)字,然后將生成的隨機(jī)數(shù)區(qū)間加1即可。
同理,生成任意非從0開(kāi)始的小數(shù)區(qū)間[d1,d2)范圍的隨機(jī)數(shù)字(其中d1不等于0),則只需要首先生成[0,d2-d1)區(qū)間的隨機(jī)數(shù)字,然后將生成的隨機(jī)數(shù)字區(qū)間加上d1即可。
d、生成任意整數(shù)
int n1 = r.nextInt();
直接使用nextInt方法即可。
e、生成[0,10)區(qū)間的整數(shù)
n2 = Math.abs(r.nextInt() % 10);```
以上兩行代碼均可生成[0,10)區(qū)間的整數(shù)。
第一種實(shí)現(xiàn)使用Random類(lèi)中的nextInt(int n)方法直接實(shí)現(xiàn)。
第二種實(shí)現(xiàn)中,首先調(diào)用nextInt()方法生成一個(gè)任意的int數(shù)字,該數(shù)字和10取余以后生成的數(shù)字區(qū)間為(-10,10),然后再對(duì)該區(qū)間求絕對(duì)值,則得到的區(qū)間就是[0,10)了。
同理,生成任意[0,n)區(qū)間的隨機(jī)整數(shù),都可以使用如下代碼:
```int n2 = r.nextInt(n);
n2 = Math.abs(r.nextInt() % n);```
#####f、生成[0,10]區(qū)間的整數(shù)
int n3 = r.nextInt(11);
n3 = Math.abs(r.nextInt() % 11);
相對(duì)于整數(shù)區(qū)間,[0,10]區(qū)間和[0,11)區(qū)間等價(jià),所以即生成[0,11)區(qū)間的整數(shù)。
#####g、生成[-3,15)區(qū)間的整數(shù)
int n4 = r.nextInt(18) - 3;
n4 = Math.abs(r.nextInt() % 18) - 3;
生成非從0開(kāi)始區(qū)間的隨機(jī)整數(shù),可以參看上面非從0開(kāi)始的小數(shù)區(qū)間實(shí)現(xiàn)原理的說(shuō)明。
#####h、幾率實(shí)現(xiàn)
按照一定的幾率實(shí)現(xiàn)程序邏輯也是隨機(jī)處理可以解決的一個(gè)問(wèn)題。下面以一個(gè)簡(jiǎn)單的示例演示如何使用隨機(jī)數(shù)字實(shí)現(xiàn)幾率的邏輯。
在前面的方法介紹中,nextInt(int n)方法中生成的數(shù)字是均勻的,也就是說(shuō)該區(qū)間內(nèi)部的每個(gè)數(shù)字生成的幾率是相同的。那么如果生成一個(gè)[0,100)區(qū)間的隨機(jī)整數(shù),則每個(gè)數(shù)字生成的幾率應(yīng)該是相同的,而且由于該區(qū)間中總計(jì)有100個(gè)整數(shù),所以每個(gè)數(shù)字的幾率都是1%。按照這個(gè)理論,可以實(shí)現(xiàn)程序中的幾率問(wèn)題。
示例:隨機(jī)生成一個(gè)整數(shù),該整數(shù)以55%的幾率生成1,以40%的幾率生成2,以5%的幾率生成3。實(shí)現(xiàn)的代碼如下:
int n5 = r.nextInt(100);
int m; //結(jié)果數(shù)字
if(n5 < 55){ //55個(gè)數(shù)字的區(qū)間,55%的幾率
m = 1;
}else if(n5 < 95){//[55,95),40個(gè)數(shù)字的區(qū)間,40%的幾率
m = 2;
}else{
m = 3;
}```
因?yàn)槊總€(gè)數(shù)字的幾率都是1%,則任意55個(gè)數(shù)字的區(qū)間的幾率就是55%,為了代碼方便書(shū)寫(xiě),這里使用[0,55)區(qū)間的所有整數(shù),后續(xù)的原理一樣。
當(dāng)然,這里的代碼可以簡(jiǎn)化,因?yàn)閹茁识际?%的倍數(shù),所以只要以5%為基礎(chǔ)來(lái)控制幾率即可,下面是簡(jiǎn)化的代碼實(shí)現(xiàn):
int n6 = r.nextInt(20);
int m1;
if(n6 < 11){
m1 = 1;
}else if(n6 < 19){
m1= 2;
}else{
m1 = 3;
}
在程序內(nèi)部,幾率的邏輯就可以按照上面的說(shuō)明進(jìn)行實(shí)現(xiàn)。
##二、java.lang.Math.Random方法
###1.使用
調(diào)用這個(gè)Math.Random()函數(shù)能夠返回帶正號(hào)的double值,該值大于等于0.0且小于1.0,即取值范圍是[0.0,1.0)的左閉右開(kāi)區(qū)間,返回值是一個(gè)偽隨機(jī)選擇的數(shù),在該范圍內(nèi)(近似)均勻分布。
例如下面的實(shí)驗(yàn)代碼
編譯通過(guò)后運(yùn)行結(jié)果如下圖

觀察會(huì)發(fā)現(xiàn)代碼的用一個(gè)循環(huán)10次循環(huán)輸出num的取值,均隨機(jī)分布在[0,3)之間!在使用Math.Random()的時(shí)候需要注意的地方時(shí)該函數(shù)是返回double類(lèi)型的值,所以在要賦值給其他類(lèi)型的變量的時(shí)候注意需要進(jìn)行塑形轉(zhuǎn)換。
###2.總結(jié)
a.通過(guò)閱讀Math類(lèi)的源代碼可以發(fā)現(xiàn),Math類(lèi)中的random方法就是直接調(diào)用Random類(lèi)中的nextDouble方法實(shí)現(xiàn)的,兩者并無(wú)差別。
只是random方法的調(diào)用比較簡(jiǎn)單,所以很多程序員都習(xí)慣使用Math類(lèi)的random方法來(lái)生成隨機(jī)數(shù)字。
b.java.util.Random()在調(diào)用的時(shí)候可以實(shí)現(xiàn)和java.Math.Random()一樣的功能,而且他具有很多的調(diào)用方法,相對(duì)來(lái)說(shuō)比較靈活。所以從總體來(lái)看,使用java.util.Random()會(huì)相對(duì)來(lái)說(shuō)比較靈活一些。
C.java.Math.Random()實(shí)際是在內(nèi)部調(diào)用java.util.Random()的,它有一個(gè)致命的弱點(diǎn),它和系統(tǒng)時(shí)間有關(guān),也就是說(shuō)相隔時(shí)間很短的兩個(gè)random比如:
double a = Math.random();
double b = Math.random();
即有可能會(huì)得到兩個(gè)一模一樣的double。
d。在使用random類(lèi)時(shí),如果想避免出現(xiàn)隨機(jī)數(shù)字相同的情況,則需要注意,無(wú)論項(xiàng)目中需要生成多少個(gè)隨機(jī)數(shù)字,都只使用一個(gè)Random對(duì)象即可。
##三、源碼分析
其實(shí)我也沒(méi)有看太懂……先把這個(gè)博客上的內(nèi)容貼過(guò)來(lái),等弄懂了再補(bǔ)自己的解釋吧……
來(lái)自
* @param seed the initial seed
* @see #setSeed(long)
*/
++++++++++++++++++帶種子數(shù)的構(gòu)造方法+++++++++++++
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方法帶參數(shù)的那個(gè)源碼++++++++++++
* @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;
}
可見(jiàn)Random的種子要求 大于0 的 。。。
+++++++++++++++nextDouble方法實(shí)現(xiàn)+++++++++++
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27))
/ (double)(1L << 53);
}
+++++++++++++++nextFloat方法實(shí)現(xiàn)+++++++++++++
public float nextFloat() {
return next(24) / ((float)(1 << 24));
}
+++++++++++++++++nextInt方法實(shí)現(xiàn):++++++++++
public int nextInt() {
return next(32);
}
可見(jiàn)所有的隨機(jī)數(shù)產(chǎn)生都和一個(gè)叫 next方法有關(guān),這個(gè)方法是這樣的:
* @since 1.1
*/
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
一般計(jì)算機(jī)的隨機(jī)數(shù)都是偽隨機(jī)數(shù),以一個(gè)真隨機(jī)數(shù)(種子)作為初始條件,然后用一定的算法不停迭代產(chǎn)生隨機(jī)數(shù),下面介紹兩種方法:
算法1:平方取中法。
1)將種子設(shè)為X0,并mod 10000得到4位數(shù)
2)將它平方得到一個(gè)8位數(shù)(不足8位時(shí)前面補(bǔ)0)
3)取中間的4位數(shù)可得到下一個(gè)4位隨機(jī)數(shù)X1
4)重復(fù)1-3步,即可產(chǎn)生多個(gè)隨機(jī)數(shù)
這個(gè)算法的一個(gè)主要缺點(diǎn)是最終它會(huì)退化成0,不能繼續(xù)產(chǎn)生隨機(jī)數(shù)。
算法2:線性同余法
1)將種子設(shè)為X0,
2)用一個(gè)算法X(n+1)=(a*X(n)+b) mod c產(chǎn)生X(n+1)
一般將c取得很大,可產(chǎn)生0到c-1之間的偽隨機(jī)數(shù)
該算法的一個(gè)缺點(diǎn)是會(huì)出現(xiàn)循環(huán)。
下面這個(gè)就簡(jiǎn)單啦。
Math類(lèi)的源代碼,Math類(lèi)中的random方法就是直接調(diào)用Random類(lèi)中的nextDouble方法實(shí)現(xiàn)的。
* @see Random#nextDouble()
*/
public static double random() {
Random rnd = randomNumberGenerator;
if (rnd == null) rnd = initRNG();
return rnd.nextDouble();
}
總結(jié)
以上是生活随笔為你收集整理的0+到10+随机数+java_Java随机数总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 小易的后花园
- 下一篇: html入门教程博客,HTML基础教程