一億個不重復的隨機數算法


最近瀏覽“程序員論壇”時發現不少好帖,增長了不少知識,現拿其中一則為例與大家共同分享心得。

  某人提出一個問題:怎樣才能生成一億個不重復的隨機數?

  問題表述起來很簡單,似乎只要弄明白什么叫隨機數以及怎樣用電腦生成隨機數,就能解決問題。

  隨機數,個人理解為一定范圍內出現的毫無規律的數,比如扔一個骰子,落在桌面上時朝上的一面所表示的數就是隨機數,這個數只能在1到6的范圍內,但具體是什么數,誰也不能肯定,因為它沒有規律。一組不重復的隨機數,對扔骰子來說就是扔出六個不一樣的數來,再比如洗一次撲克牌,洗完后就是54張不重復的隨機數。

  第二個問題,怎么樣用電腦生成隨機數?只要調用某個語言的某個函數即可。其實電腦是沒辦法生成真正的隨機數,因為電腦是高度有規律的機器,讓它生成一個沒規律的數,根本辦不到。平時程序員用某個函數生成的隨機數,只是利用某個算法弄出來的偽隨機數,看起來像,其實不是,能解決問題就行。

  回到這個帖子所描述的問題上來。生成一億個不重復的隨機數,最直接的算法就是每用函數生成一個數,就把它放在一個筐里,第一個數直接放到筐里,以后生成的數在放到筐里之前和筐里的每一個數比較一番,一旦發現筐里有和新生成的數一樣的數時,丟掉這個新生成的數,再接着生成數。

  毫無疑問,這種算法的效率非常低,看看其中的比較次數就知道了,最差的次數趨於無窮次。也就是說到后來,幾乎生成不了和以往不同的數。

  當然還可以將這個算法升級為效率高得多的算法,每生成一個數,把這個數從隨機數生成器取的范圍中去掉,比如要生成10個隨機數,第一次生成一個3,我把3從隨機數的范圍中去掉,第二次只從1到9這個范圍內找。3對應4,4對應5……9對應10。這樣就不存在比較的環節,然而又多出一個對應的環節,每生成一個數之后就要把剩下的數重新對應一遍,效率也不容樂觀。

  目前以我為代表的普通程序員的想象力也就到此為止,想不出什么高級解決辦法,就當扔一塊磚頭出來,下面就把真正的碧玉——數學家級程序員的算法隆重介紹請出來。

  我們先用另一種眼光來看不重復的隨機數:加密。把一個能看懂的英文字符串打亂字母的順序,變成不可讀,這就是加密。但必須得有規律地打亂,字母a對應另外一個固定的字母Ax,字母b對應另外一個固定的字母Bx,以此類推,而且必須一一對應的。那么字符串“ab…z”這26個字母對應的26個加密字母“AxBx和Zx”就可以看成是對應范圍a到z的不重復的偽隨機數,這就是數學家的算法的來源。

  看看回帖者的原文:

  “可以采用32bit RSA算法
  設A從2~(N-1) 
  C=(A EXP D)  mod N 
  滿足如下條件: 
  D是素數,N是兩個素數(P,Q)之積, 
  (D * E) mod ((P-1) * (Q-1))=1 
  因為:若 
  C=(A EXP D)mod N 
  有: 
  A=(C EXP E) mod N 
  所以,C與A 一一對應。 
  所以,對於A=2~(N-1),有不重復,無遺漏的偽隨機碼C。”

 

  凡是稍微扯上一點數學,尤其是高等數學的問題,我等泛泛之輩看起來就有點費勁,這里雖然文字不長,但是還得慢慢來看。

  這里面RSA算法是密碼學三大算法之一(RSA、MD5、DES),是一種不對稱密碼算法。說如果滿足條件:D是素數,N是兩個素數(P,Q)之積,(D * E) mod ((P-1) * (Q-1))=1,那么存在C與A(范圍從2到N-1)一一對應,且C=(A EXP D)mod N。A是一個有順序的數,C就是一個看似無規律的偽隨機數。Mod運算表示求模,例如7Mod3=1。意思是7除以3余1。類似地8Mod3=2,9Mod3=0。EXP表示前面數的后面數次方,AEXPD表示A的D次方。這兩個運算清楚了,其它的也就沒什么困難的了,*是乘法的意思,大多數理科生都清楚。

  搜了一下網絡,還得加上一些條件,1,P和Q不能一樣。2,e<(P-1)(Q-1)且e與(P-1)(Q-1)的最大公因數為1。

  下面用一個例子來試驗一下,看看這個算法有多神奇。

  設N=15,P=5,Q=3,則A為2到14的數。現在要產生2到14的偽隨機數。取D為3,E為3,

C2=(2EXP3)mod15 = 8,  

C3=(3EXP3)mod 15 = 12,   

C4  = (4EXP3)mod 15= 4,   

C5  = (5EXP3)mod 15= 5,   

C6  = (6EXP3)mod 15= 6,   

C7  = (7EXP3)mod 15= 13,   

C8  = (8EXP3)mod 15= 2,   

C9  = (9EXP3)mod 15= 9,   

C10  = (10EXP3)mod 15= 10,   

C11  = (11EXP3)mod 15= 11,   

C12  = (12EXP3)mod 15= 3,   

C13  = (13EXP3)mod 15= 7,   

C14  = (14EXP3)mod 15= 14。

  比較完美,如果數再大一點,可能看起來更隨機一些。

  由這個算法產生的1億的偽隨機數,效率那可是相當的高,只不過運算時要用到大數運算庫。在一些講求效率的場合應用的話,再做一些對應上的處理,升級一下算法,那定是相當的完美。

  由此可以看出,算法的優化,如果僅僅停留在大腦能夠想象到的小學數學的階段,那是遠遠達不到要求。一個優秀的程序員,還需要加深對離散數學的理解,雖然,這次提到的算法已經深入到了數論的層次上了,但是RSA算法已經是應用非常廣泛的算法,對其稍加變通,便可以發揮出更加不可思議的作用。程序員還是需要多學習算法,多學習數學,才能發揮出超出一般程序員的不可思議的能力。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM