Java中隨機數的產生方式與原理詳解_java

來源:互聯網
上載者:User

Java中隨機數的產生方式與原理

查閱隨機數相關資料,特做整理

首先說一下java中產生隨機數的幾種方式

  1. 在j2se中我們可以使用Math.random()方法來產生一個隨機數,這個產生的隨機數是0-1之間的一個double,我們可以把他乘以100,他就是個100以內的隨機數字,這個在j2me中沒有。
  2. 在java.util這個包裡面提供了一個Random的類,我們可以建立一個Random的對象來產生隨機數,他可以生產隨機整數、隨機float、隨機double、隨機long,這個也是我們在j2me的程式裡經常用的一個取隨機數的方法。
  3. 在我們的System類中有一個currentTimeMillis()方法,這個方法返回一個從1970年1月1號0點0分0秒到目前的一個毫秒數,傳回型別是long,我們可以拿他作為一個隨機數,我們可以拿他對一些數模數,就可以把他限制在一個範圍之內啦。

EN。。。其實在Random的預設構造方法裡也是使用上面第三種方法進行隨機數的產生的。

對於方法二中的Random類有兩種構建方式:帶種子和不帶種子

不帶種子:此種方式將會返回隨機的數字,每次運行結果不一樣,相當於用System.currentTimeMillis()作種子。

帶種子:此種方式,無論程式運行多少次,返回結果都是一樣的。如果用相同的種子建立兩個Random執行個體,則對每個執行個體進行相同的方法調用序列,它們將產生並返回相同的數字序列。

偽隨機數

電腦中的隨機數都是偽隨機數

下面看這樣一個C程式:

// rand_1.cpp#include <stdlib.h>static unsigned int RAND_SEED;unsigned int random(void){  RAND_SEED = (RAND_SEED*123+59)%65536;  return (RAND_SEED);}void random_start(void){  int temp[2];  movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);  RAND_SEED = temp[0];}void main(){  unsigned int i,n;  random_start();  for(i=0;i<10;i++)     printf("#u\t",random());  printf("\n");}

它完整地闡述了隨機數產生的過程:

首先,

movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);

這個函數用來移動記憶體資料,其中FP_SEG(far pointer to segment)是取temp數組段地址的函數,FP_OFF(far pointer to offset)是取temp數組相對位址的函數,movedata函數的作用是把位於0040:006CH儲存單元中的雙字放到數組temp的聲明的兩個儲存單元中。這樣可以通過temp數組把0040:006CH處的一個16位的數送給RAND_SEED。
其次,

RAND_SEED=(RAND_SEED*123+59)%65536;

是用來計算隨機數的方法,隨機數的計算方法在不同的電腦中是不同的,即使在相同的電腦中安裝的不同的作業系統中也是不同的。我在linux和windows下分別試過,相同的隨機種子在這兩種作業系統中產生的隨機數是不同的,這說明它們的計算方法不同。

然後,

movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);

隨機種子為什麼要在記憶體的0040:006CH處取?0040:006CH處存放的是什嗎?

學過《電腦群組成原理與介面技術》這門課的人可能會記得在編製ROM BIOS時鐘中斷服務程式時會用到Intel 8253定時/計數器,它與Intel 8259中斷晶片的通訊使得中斷服務程式得以運轉,主板每秒產生的18.2次中斷正是處理器根據定時/記數器值控制中斷晶片產生的。在我們電腦的主機板上都會有這樣一個定時/記數器用來計算當前系統時間,每過一個時鐘訊號周期都會使記數器加一,而這個記數器的值存放在哪兒呢?沒錯,就在記憶體的0040:006CH處,其實這一段記憶體空間是這樣定義的:

TIMER_LOW DW ? ;地址為 0040:006CH
TIMER_HIGH DW ? ;地址為 0040:006EH
TIMER_OFT DB ? ;地址為 0040:0070H

時鐘中斷服務程式中,每當TIMER_LOW轉滿時,此時,記數器也會轉滿,記數器的值歸零,即TIMER_LOW處的16位二進位歸零,而TIMER_HIGH加一。rand01.c中的

movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);

正是把TIMER_LOW和TIMER_HIGH兩個16位位元放進temp數組,再送往RAND_SEED,從而獲得了“隨機種子”。
現在,可以確定的一點是,隨機種子來自系統時鐘,確切地說,是來自電腦主板上的定時/計數器在記憶體中的記數值。

EN...沒有最後。。lvl--

再看一段代碼:

//rand_2.cpp#include <iostream>#include <cstdlib>using namespace std;int main(){  srand((unsigned)time(NULL));  unsigned int r=rand();  cout<<"r = "<<r<<endl; //根據C++ 98標準,可以不用return語句來介紹main函數  return 0;}

這裡使用者和其他程式沒有設定隨機種子,則使用系統定時/計數器的值做為隨機種子,所以,在相同的平台環境下,編譯產生exe後,每次運行它,顯示的隨機數會是偽隨機數,即每次運行顯示的結果會有不同。

總結

隨機數是由隨機種子根據一定的計算方法計算出來的數值。所以,只要計算方法一定,隨機種子一定,那麼產生的隨機數就不會變。在相同的平台環境下,編譯產生exe後,每次運行它,顯示的隨機數都是一樣的。這是因為在相同的編譯平台環境下,由隨機種子產生隨機數的計算方法都是一樣的,再加上隨機種子一樣,所以產生的隨機數就是一樣的。

只要使用者或第三方不設定隨機種子,那麼在預設情況下隨機種子來自系統時鐘(即定時/計數器的值)

感謝閱讀,希望能協助到大家,謝謝大家對本站的支援!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.