JAVA認證培訓輔導:隨機整數的產生

來源:互聯網
上載者:User
隨機

  使用Java 2 SDK基礎類庫產生隨機數的方法很多。但是如果你跟不上這些類庫的更新腳步,你有可能正在使用的是一種低效的隨機數產生機制,更糟糕的是:你有可能得到的不是均勻分布的隨機數。本文將向你展示一種較為可靠的隨機數產生方法,同時與其他方法進行比較。

  自從JDK最初版本發布起,我們就可以使用java.util.Random類產生隨機數了。在JDK1.2中,Random類有了一個名為nextInt()的方法:

  public int nextInt(int n)

  給定一個參數n,nextInt(n)將返回一個大於等於0小於n的隨機數,即:0 <= nextInt(n) < n。

  你所要做的就是先聲明一個Random的對象,在調用其nextInt(n)函數以返回隨機值。

  這裡有個樣本,下面的程式碼片段將產生很多隨機數並輸出它們的平均值:

  int count = 1000000;
  int range = Integer.MAX_VALUE / 3 * 2;
  double sum = 0;
  Random rand = new Random();
  for (int i=0; i 
  sum += rand.nextInt(range);
  }
  System.out.println(sum/count);

  執行了1000000次迴圈之後,得到的平均值基本上就處於隨機數範圍的中點(midpoint)。

  到目前為止,事情還並不複雜,但是我們會問為什麼要使用nextInt(n)?考慮一下的隨機數產生方法:

  (1)使用老的方法nextInt(),沒有制定數值範圍

  (2)用Math.abs()靜態函數得到(1)中產生值的絕對值

  (3)對(2)的結果進行模數運算(%),得到期望範圍類的值

  我們說nextInt(n)要比上述方法更好,為什麼呢?參考以下的程式碼片段:

  sum = 0;
  for (int i=0; i 
  sum += Math.abs(rand.nextInt()) % range;
  }
  System.out.println(sum/count);

  不難發現,每次迴圈都多出了幾步運算。事實上,這種隨機數產生的方法存在著以下三個問題:

  首先,nextInt()返回的值是趨於均勻分布在Integer.MIN_VALUE 和 Integer.MAX_VALUE之間的。如果你取Integer.MIN_VALUE的絕對值,得到的仍然不是一個正數。事實上,Math.abs(Integer.MIN_VALUE)等於Integer.MIN_VALUE。因此,存在著這樣一種情況(雖然很少見):rand.nextInt()=Integer.MIN_VALUE,經過取絕對值Math.abs(rand.nextInt())之後,得到是一個負數。這種幾率為 1/(2^31),在我們的測試中不太可能發生——迴圈次數只有1000000次。

  其次,當你對nextInt()模數時,你使結果的隨機性大打折扣。隨機數中較小的值出現的幾率更大一些。這就是眾所周知的偽隨機數產生,因此我們不是用模數的方法。

  最後,也可能是最糟糕的:隨機數不是均勻分布。如果你執行了上述的兩段代碼,第一段代碼的結果將會大於715,000,000,考慮到數值範圍的中點(midpoint)是715,827,882,所以這是一個可以接受的結果。然而,你會吃驚的發現第二段代碼得到的平均值肯定不會超過600,000,000。

  為何第二段代碼的結果會如此的偏差?糾其本質,問題出在數值分布的不均勻。當你進行模數運算時,你將過大的數轉換成了較小的。這使得較小的數更容易產生。

  使用nextInt(range)將會解決上述的三個問題。

  還有一種隨機數產生方法——使用Math.random()。這個方法的效果如何?

  sum = 0;
  for (int i=0; i 
  sum += (int)(Math.random() * range);
  }
  System.out.println(sum/count);

  很好,使用random()不會碰到nextInt()的麻煩。你不會得到負數傳回值,沒有使用模數運算,值分布也是均勻的。還有什麼問題嗎?你有沒有考慮到Math.random()使用了浮點運算,而nextInt()和nextInt(range)只有整數操作?Math.random()可能會慢上四倍。再加上從浮點到整數的類型轉換,整個運算將會更慢。

  好了,經過一番比較,我們發現使用nextInt(range)產生隨機數更為有效,因為它避免了其他方法的種種弊端。

  最後再給出一段代碼,通過測試可以比較本文提到的幾種隨機數產生方法。

  import java.util.*;
  import java.text.*;
  public class RandomTest {
  public static void main(String args[]) {
  NumberFormat nf = NumberFormat.getInstance();
  int count = 1000000;
  int range = Integer.MAX_VALUE / 3 * 2;
  System.out.println("Midpoint: " + nf.format(range/2));
  double sum = 0;
  Random rand = new Random();
  for (int i=0; i 
  sum += rand.nextInt(range);
  }
  System.out.println("Good : " + nf.format(sum/count));
  sum = 0;
  for (int i=0; i 
  sum += Math.abs(rand.nextInt()) % range;
  }
  System.out.println("Bad : " + nf.format(sum/count));
  sum = 0;
  for (int i=0; i 
  sum += (int)(Math.random() * range);
  }
  System.out.println("Longer : " + nf.format(sum/count));
  }
  }



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.