提起隨機(jī)數(shù),大家一定都不陌生。無論是在計(jì)算機(jī)科學(xué)領(lǐng)域,還是現(xiàn)實(shí)生活中,隨機(jī)數(shù)的作用都不可小覷。
但隨機(jī)數(shù)究竟是怎么一會事?它的作用是什么?它有事如何產(chǎn)生的?
本文會著重談計(jì)算機(jī)的隨機(jī)數(shù)以及產(chǎn)生算法,偏理論的只是會放到另一篇博客上隨機(jī)數(shù)那些事
想要討論隨機(jī)數(shù),首先應(yīng)該明確一下隨機(jī)數(shù)的定義。畢竟這個東西比較虛,并不像算法那樣明確。在各大網(wǎng)上也沒有給出很好的定義。
那…就不死摳定義了。
隨機(jī)數(shù)一般來說符合下面這幾個性質(zhì)。
它產(chǎn)生時后面那個數(shù)與前面的毫無關(guān)系
給定樣本的一部分和隨機(jī)算法,無法推出樣本的剩余部分
其隨機(jī)樣本不可重現(xiàn)
另外還要說一下統(tǒng)計(jì)學(xué)偽隨機(jī)數(shù)概念,劃重點(diǎn)
統(tǒng)計(jì)學(xué)偽隨機(jī)性。統(tǒng)計(jì)學(xué)偽隨機(jī)性指的是在給定的隨機(jī)比特流樣本中,1的數(shù)量大致等于0的數(shù)量,同理,“10”“01”“00”“11”四者數(shù)量大致相等。類似的標(biāo)準(zhǔn)被稱為統(tǒng)計(jì)學(xué)隨機(jī)性。滿足這類要求的數(shù)字在人類“一眼看上去”是隨機(jī)的。(摘自百度詞條)
實(shí)際上這也是在計(jì)算機(jī)中對偽隨機(jī)數(shù)優(yōu)劣的概念。
continue->
偽隨機(jī)數(shù),也就是我們c++中常用的隨機(jī)數(shù)。為什么說它是“偽”隨機(jī)呢?其實(shí)只要稍微詳細(xì)的了解過c++ rand函數(shù)的人應(yīng)該都能懂得這一點(diǎn)。
因?yàn)橛?jì)算機(jī)本身并不能夠產(chǎn)生和隨機(jī)數(shù),只能通過產(chǎn)生一組循環(huán)節(jié)很長的數(shù)來“偽造”隨機(jī)。
c++的rand函數(shù)實(shí)際上只是根據(jù)你提供的種子計(jì)算出來的一組循環(huán)節(jié)很長的數(shù)。只要兩次提供的種子是一樣的,那么rand函數(shù)提供的隨機(jī)數(shù)也是一樣的。
可能有好奇的小伙伴就要問了,你說循環(huán)節(jié)很長,那到底長到什么程度呢?
經(jīng)過不懈的努力,筆者成功弄到了rand()函數(shù)在LINUX系統(tǒng)下的實(shí)現(xiàn):
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
( 該代碼摘自CSDN 原文鏈接)
通過這個算法我們可以推知,rand函數(shù)的循環(huán)節(jié)應(yīng)該是在32768(2的15次方)以內(nèi)。
( 所以我白測試了是嗎 )
做這些測試實(shí)際上就是想說,在計(jì)算機(jī)方面。目前來說,如果不借助外部幫助,是無法達(dá)到真隨機(jī)的。
計(jì)算機(jī)隨機(jī)數(shù)的產(chǎn)生,我在講偽隨機(jī)時已經(jīng)水過做過介紹了,也就不多說。
你以為我會幫忙把前面的代碼拷過來嗎?想太多了,自己翻頁去。
( 本來想放點(diǎn)圖可能可以增加可讀性,但好像放不了什么… )
這里我主要想講的是關(guān)于計(jì)算機(jī)在沒有外界幫助下為什么不能產(chǎn)生真隨機(jī)數(shù)。
真隨機(jī)數(shù)的產(chǎn)生應(yīng)該是與之前的數(shù)是沒有任何關(guān)聯(lián)的( 論證過 ),那么在計(jì)算機(jī)中想對應(yīng)的就是產(chǎn)生隨機(jī)數(shù)的函數(shù)應(yīng)該不需要調(diào)用任何參數(shù)( 因?yàn)橐坏┱{(diào)用了的參數(shù),那么這個隨機(jī)數(shù)的產(chǎn)生就會與參數(shù)相關(guān) )那么對于計(jì)算機(jī)來說,如何不調(diào)用任何參數(shù)并且產(chǎn)生不同的數(shù)呢?
這個…好像做不到。
這個換一個思維來解釋好一點(diǎn)。因?yàn)橛?jì)算機(jī)是一個絕對理智的存在,也就是說,計(jì)算機(jī)的一切行為都是可預(yù)測可推導(dǎo)的。而這恰恰違背了我們隨機(jī)數(shù)標(biāo)準(zhǔn)中的第二條,即不可推斷。對于計(jì)算機(jī)的任何程序,如果使用完全相同的參數(shù)來調(diào)用,它所輸出的結(jié)果一定是完全一樣的
農(nóng)夫山泉不生產(chǎn)水,他們只是大自然的搬運(yùn)工
計(jì)算機(jī)不生產(chǎn)數(shù)據(jù),它只是數(shù)據(jù)的加工廠。
不是重點(diǎn),知道了就好。
真隨機(jī)數(shù)生成器是一種通過物理過程而不是計(jì)算機(jī)程序來生成隨機(jī)數(shù)字的設(shè)備。
這樣的設(shè)備通常是基于一些能生成低等級、統(tǒng)計(jì)學(xué)隨機(jī)的“噪聲”信號的微觀現(xiàn)象,如熱力學(xué)噪聲、光電效應(yīng)和量子現(xiàn)象。這些物理過程在理論上是完全不可預(yù)測的,并且已經(jīng)得到了實(shí)驗(yàn)的證實(shí)。硬件隨機(jī)數(shù)生成器通常由換能器、放大器和模擬數(shù)字轉(zhuǎn)換器組成。其中換能器用來將物理過程中的某些效果轉(zhuǎn)換為電信號,放大器及其電路用來將隨機(jī)擾動的振幅放大到宏觀級別,而模擬數(shù)字轉(zhuǎn)換器則用來將輸出變成數(shù)字,通常是二進(jìn)制的零和一。通過重復(fù)采樣這些隨機(jī)的信號,一系列的隨機(jī)數(shù)得以生成。
(摘自百度詞條原文鏈接)
首先是用于檢驗(yàn)程序。
估計(jì)這是大部分OIer的用法,拿一個隨機(jī)數(shù)生成器去驗(yàn)證程序的速度,以及是否會RE( 正確率是測不了的,畢竟自己手推答案比較慢 )。
然后的話是某些算法的需要
這里因?yàn)樗惴ㄌ?,筆者也就大概介紹一下:
大家熟悉的平衡樹treap,它是通過生成隨機(jī)權(quán)值引導(dǎo)進(jìn)行旋轉(zhuǎn)操作來使樹接近平衡。
相對常見的模擬退火就是隨機(jī)算法的一個極致實(shí)現(xiàn)。它通過完全隨機(jī)的操作變換解,使其不斷接近正解。也是大家在OI中最多的用法。
可能大家相對陌生的遺傳算法中也有隨機(jī)數(shù)的體現(xiàn)。主要表現(xiàn)在交叉和變異兩方面上。
可能大家聽都沒通說過的Pollard_Rho算法,就是超大數(shù)的分解質(zhì)因數(shù)。因?yàn)閿?shù)字過大無法用O(N)的算法。此時我們就通過隨機(jī)數(shù)去“猜”質(zhì)因數(shù):不斷生成隨機(jī)值,判斷是否出現(xiàn)兩者之差為因子。(因?yàn)閮烧卟顬橹付ㄖ档某霈F(xiàn)概率會比一個個猜大一倍),然后不斷遞歸隨機(jī)到的那個因子和那個數(shù)初一因子的另一半,直到找到質(zhì)因子。具體算法比較復(fù)雜。有機(jī)會單獨(dú)寫一篇講。模板題傳送門
然后與遺傳算法類似的粒子群算法,隨機(jī)主要出現(xiàn)在單個粒子的更新上。
蟻群算法有用到,但因?yàn)檫^于冷門,就不多做介紹了。
( 感覺隨機(jī)數(shù)好像也就這么點(diǎn)用,在密碼學(xué)統(tǒng)計(jì)學(xué)中用的比較多 )
在講隨機(jī)數(shù)算法之前,應(yīng)該先講講隨機(jī)數(shù)優(yōu)劣的判定。
畢竟只有清除了隨機(jī)數(shù)的優(yōu)劣,我們才能說如何生成優(yōu)質(zhì)隨機(jī)數(shù)。
在這里我們就要用到前面說的統(tǒng)計(jì)學(xué)偽隨機(jī)性:
統(tǒng)計(jì)學(xué)偽隨機(jī)性。統(tǒng)計(jì)學(xué)偽隨機(jī)性指的是在給定的隨機(jī)比特流樣本中,1的數(shù)量大致等于0的數(shù)量,同理,“10”“01”“00”“11”四者數(shù)量大致相等。類似的標(biāo)準(zhǔn)被稱為統(tǒng)計(jì)學(xué)隨機(jī)性。滿足這類要求的數(shù)字在人類“一眼看上去”是隨機(jī)的。(我?guī)兔Π嵯聛砹耍?/p>
結(jié)合計(jì)算機(jī)隨機(jī)數(shù)的特性,我們能夠得出以下三項(xiàng)判斷隨機(jī)數(shù)優(yōu)劣的性質(zhì):
隨機(jī)程度,即隨機(jī)算法是否足夠復(fù)雜,隨機(jī)數(shù)之間會不會存在明顯聯(lián)系。
分布范圍,即是否存在隨機(jī)數(shù)在分布區(qū)域內(nèi)大量出現(xiàn)偏大偏小的現(xiàn)象。分布是否足夠平均。
循環(huán)長度,即是否會在大量調(diào)用時很快地出現(xiàn)循環(huán)的情況。
有了這些評判規(guī)則,我們就比較好學(xué)習(xí)優(yōu)質(zhì)隨機(jī)數(shù)的生成。
終于到了塞實(shí)貨時間。
水不動了
這里前三個我講一下在rand函數(shù)調(diào)用基礎(chǔ)上自己做一點(diǎn)小操作來產(chǎn)生三種不同特性的隨機(jī)數(shù)。
第四個專題講MT19337算法(重點(diǎn),絕對的重點(diǎn)),也就是目前優(yōu)質(zhì)隨機(jī)數(shù)生成的普遍算法。
這種隨機(jī)數(shù)主要是針對退火算法之類的需要用隨機(jī)數(shù)來修正答案的。
既然是修正答案,那么我們希望最好是來回?cái)[動,一正一負(fù)的。
這種隨機(jī)數(shù)的特點(diǎn)便是通過一部分人工處理,將原本的rand函數(shù)產(chǎn)生的隨機(jī)數(shù)變成正負(fù)交替的。
int f = 3000 ;
int change = 0.999 ; // f和change是用來控制隨機(jī)數(shù)幅度不斷變小的
int con = -1 ;
int g = 1 ; // 控制正負(fù)交替
int newrand ( ) {
f *= change ;
g *= con ;
int tmp = f * g * rand ( ) ;
return tmp ;
}
這種隨機(jī)數(shù)的產(chǎn)生引入了退火的思路,當(dāng)然,你也可以直接使用算法中現(xiàn)成的溫度來控制。
這種主要是用于平衡樹treap的,特點(diǎn)就是在保證單個數(shù)隨機(jī)的情況下在整體上保證分布比較平均。
實(shí)現(xiàn)原理也沒什么好講的,上代碼就完事了。
int p ; // 希望的分布位置
int newrand ( ) {
int tmp = ( p + rand ( ) ) / 2 ; // 通過取于分布位置的平均數(shù),是產(chǎn)生的數(shù)更加靠近希望分布
return tmp ;
}
當(dāng)然,如果有人真的需要非常接近真隨機(jī)的數(shù)。也就是多次運(yùn)行程序也不會出現(xiàn)相同的情況。那就需要用到一定的外部干擾了。
首先是clock函數(shù),上文已經(jīng)說過,一個程序在不斷調(diào)用期間。每一次的運(yùn)行時間都會有細(xì)小的變化。我們就可以利用好這個變化。每次調(diào)用完后都重置一次隨機(jī)數(shù)種子。
還有一個可能大家都會忽視的方法。計(jì)算機(jī)本身的誤差。眾所周知,計(jì)算機(jī)在做浮點(diǎn)運(yùn)算時是會產(chǎn)生精度損失的,那么我們也可以利用這個特點(diǎn)輔助clock調(diào)整種子(畢竟程序調(diào)用時間相同其實(shí)可能性也不小,畢竟clock只精確到s/1000)。
int count ;
int realrand ( ) {
count ++ ;
int t = clock ( ) + 1 ; // 使用當(dāng)前時間
for ( int i = 1 ; i < 12121307 ; i ++ ) { // 降速(如果放到具體代碼里面使用可以將此參數(shù)調(diào)低)
t += rand ( ) ;
}
t += clock ( ) ; // 降速后擴(kuò)大時間變化
t *= -1234 ;
srand ( t * count + rand ( ) ) ; // 重置隨機(jī)數(shù)種子
return rand ( ) ;
}
筆者經(jīng)過大量實(shí)驗(yàn),發(fā)現(xiàn)該函數(shù)前三個數(shù)出現(xiàn)重復(fù)幾率相對會比較大(7~9%)建議從第四個開始使用。
上面的代碼我并沒用用精度損失來隨機(jī)化,因?yàn)槲野l(fā)現(xiàn)同一個式子的進(jìn)度損失值太小,以至于幾乎不會發(fā)生什么改變,所以并沒有使用。
因?yàn)槿齻€函數(shù)實(shí)際上都是在調(diào)用rand()函數(shù),所以實(shí)際上他們的優(yōu)質(zhì)程度是與rand()函數(shù)相同的。記得我之前題的判斷隨機(jī)數(shù)優(yōu)劣的標(biāo)準(zhǔn)嗎?
隨機(jī)程度,即隨機(jī)算法是否足夠復(fù)雜,隨機(jī)數(shù)之間會不會存在明顯聯(lián)系。
分布范圍,即是否存在隨機(jī)數(shù)在分布區(qū)域內(nèi)大量出現(xiàn)偏大偏小的現(xiàn)象。分布是否足夠平均。
循環(huán)長度,即是否會在大量調(diào)用時很快地出現(xiàn)循環(huán)的情況。
就是這個
我們來逐條分析。
首先,隨機(jī)程度方面,雖然你們之前看過rand()函數(shù)代碼,可能清楚數(shù)字之間的關(guān)聯(lián)
。但在實(shí)際運(yùn)用中,這個數(shù)字之間的關(guān)聯(lián)還是基本可以忽略的。所以在隨機(jī)程度方面,rand()函數(shù)還是能夠勉強(qiáng)通過的。
在平均分布方面,單看代碼可能感覺不出來。
那么,筆者就做一個測試:
#include<iostream>
#include<stdlib.h>
using namespace std ;
int data[1000] ;
int main ( ) {
for ( long long i = 1 ; i <= 100000000 ; i ++ ){
int tmp = rand ( ) % 100000 ; //生成一個100000以內(nèi)的隨機(jī)數(shù)
data[ tmp / 10 ] ++ ; //統(tǒng)計(jì)出現(xiàn)次數(shù)
}
for ( int i = 1 ; i <= 100 ; i ++ ) {
cout << data[i] << endl ;
}
cout << ' ok ' << endl ;
return 0 ;
}
最后結(jié)果:
從中我們可以看到,這個分布還是非常平均的。
循環(huán)長度…
這個主要就是rand()函數(shù)的硬傷了,32768這個長度真的挺不夠用的。在需要大量調(diào)用rand()函數(shù)的算法中(比如退火),基本都會把rand()卡出循環(huán)。
那有沒有既優(yōu)質(zhì)又循環(huán)節(jié)長的算法呢?
這個很重要,所以標(biāo)題升了一級
這個是目前產(chǎn)生優(yōu)質(zhì)偽隨機(jī)數(shù)的普遍算法
在C++11,python等多種語言中都有使用# 旋轉(zhuǎn)算法簡介
梅森旋轉(zhuǎn)算法,也可以寫作MT19937。是有由松本真和西村拓士在1997年開發(fā)的一種能快速產(chǎn)生優(yōu)質(zhì)隨機(jī)數(shù)的算法。
其實(shí)這個算法跟梅森沒有什么關(guān)系,它之所以叫做是梅森旋轉(zhuǎn)算法是因?yàn)樗难h(huán)節(jié)是2^19937-1,這個叫做梅森素?cái)?shù)。
這個算法之所以說是產(chǎn)生優(yōu)質(zhì)隨機(jī)數(shù),是因?yàn)樗谘h(huán)節(jié)特別長的情況下(2^19337-1)還能保證平均分布。
我在這里大概給一個概念:
銀河系中的恒星數(shù)量級10^11
撒哈拉沙漠中的沙子數(shù)數(shù)量級是10^26
宇宙中目前可觀察的粒子數(shù)量級是10^87
2^19937數(shù)量級是10^6001
這個比較大概心里有數(shù)了吧
相差的已經(jīng)不止是一個數(shù)量級了
同時他在623維中的分布都十分的均勻(這個不用理解)
知道分布平均就好了
(梅森鎮(zhèn)樓)
->continue
分析這個算法的原理需要的前置知識在網(wǎng)上講的都比較繞,我在這里就通俗的科普一下,主要是認(rèn)識這幾個名詞。
(用詞不準(zhǔn)確輕噴)
這個,就當(dāng)它是隨機(jī)數(shù)發(fā)生器就完事了,不要太去糾結(jié)定義。后面會講。
簡單的說來就是沒法化簡的多項(xiàng)式
比如 y=x4+x2 就可以化簡為(x2+1)x2
也是知道就好,不用過于追求定義
計(jì)算機(jī)的一個二進(jìn)制單位(0或1)就是一級
這個應(yīng)該比較好理解
這個應(yīng)該是網(wǎng)上看別的博客最繞的知識點(diǎn)
簡單地理解成你要對這個寄存器干什么的一個函數(shù)就好了
(看到這里應(yīng)該還沒懵吧)
這個…
還要我科普嗎?
就是兩個數(shù),如果都是0或都是1就輸出0,一個1一個0輸出1.
->continue
這個旋轉(zhuǎn)算法實(shí)際上是對一個19937級的二進(jìn)制序列作變換。
首先我們達(dá)成一個共識:
一個長度為n的二進(jìn)制序列,它的排列長度最長為2^n。
當(dāng)然這個也是理論上的,實(shí)際上可能因?yàn)槟承┎僮鞑划?dāng),沒挺到2^n個就開始循環(huán)了。
那么如何將這個序列的排列撐滿2^n個,就是這個旋轉(zhuǎn)算法的精髓。
如果反饋函數(shù)的本身+1是一個本原多項(xiàng)式,那么它的循環(huán)節(jié)達(dá)到最長,即2^n-1
這個數(shù)學(xué)證明本文不作過多論述,有興趣者可以自己查閱資料
個人感覺單講知識點(diǎn)挺難懂的(筆者就是這么被坑的)
我們就拿一個4級的寄存器模擬一下:
我們這里使用的反饋函數(shù)是 y=x^4+x^2+x+1(這個不是本原多項(xiàng)式,只是拿來好理解)
這個式子中x^4,x^2,x的意思就是我們每次對這個二進(jìn)制序列的從后往前數(shù)第4位和第2位做異或運(yùn)算 ,然后x的意思是我們再拿結(jié)果和最后一位做異或運(yùn)算。把最后的結(jié)果放到序列的開頭,整個序列后移一位,最后一位舍棄。
初始數(shù)組 { 1 , 0 , 0 , 0 } (為什么不是 0,0,0,0 你們可以自己想想,文章末尾揭曉)
將它的第四位和第二位抓出來做異或運(yùn)算
把剛剛的運(yùn)算結(jié)果和最后一位再做一次運(yùn)算
把最后的運(yùn)算結(jié)果放到第一位,序列后移。最后一位被無情的拋棄
這就是一次運(yùn)算,然后這個算法就是不斷循環(huán)這幾步,從而不斷偽隨機(jī)改變這個序列。
上圖是一個網(wǎng)上找的一個4級寄存器的模擬過程
大家可以推一下,它所使用的反饋函數(shù)(y=x^4+x+1)
因?yàn)檫@個是本原多項(xiàng)式
所以他最后的循環(huán)節(jié)是2^4-1=15
運(yùn)算結(jié)果如下:
(圖片摘自原文鏈接)
大家可以看到這個運(yùn)算結(jié)果包含到了2^4-1~1中的所有數(shù)字,并且沒有循環(huán)。
同時擁有很好的隨機(jī)性。
可能又有人有疑問了:
這個運(yùn)算結(jié)果明明能看出規(guī)律啊,我不是看到了很多1的平行四邊形嗎?
醒醒
這是二進(jìn)制數(shù)。
如果你把它轉(zhuǎn)化成數(shù)字。
8 12 14 15 7 11 …
能看出規(guī)律?
可能有人到這里還沒看出“旋轉(zhuǎn)”在哪里。
因?yàn)槲覀兠看斡?jì)算出來的結(jié)果會放在開頭,序列后移一位??雌饋砭拖駭?shù)組在向后旋轉(zhuǎn)…
(本來想做gif的,后來不知道怎么做出旋轉(zhuǎn))
大家自行腦補(bǔ)
->continue
1.隨機(jī)程度:
這個應(yīng)該不用說了,認(rèn)真看這個原理的都應(yīng)該清楚它的隨機(jī)程度比rand()不知道高到哪里去了。如果說rand()還能夠用公式表達(dá)的話,這個19337已經(jīng)無法通過算式表達(dá)了。
2.分布范圍:
這里筆者比較懶就不做證明了。有興趣的可以拿上面的代碼自行檢測。
3.循環(huán)長度:
其實(shí)這點(diǎn)我可以直接跳過的。19337算法最不慌的就是循環(huán)長度。2^19337的循環(huán)長度根本不需任何算法。畢竟人家這個算法的循環(huán)長度是與空間大小成指數(shù)級關(guān)系的……
(筆者很懶,直接搬原代碼出處的代碼)
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <time.h>
using namespace std;
bool isInit;
int index;
int MT[624]; //624 * 32 - 31 = 19937
隨機(jī)種子
void srand(int seed)
{
index = 0;
isInit = 1;
MT[0] = seed;
for(int i=1; i<624; i++)
{
int t = 1812433253 * (MT[i-1] ^ (MT[i-1] >> 30)) + i;
MT[i] = t & 0xffffffff; //取最后的32位
}
}
梅森旋轉(zhuǎn)
void generate()
{
for(int i=0; i<624; i++)
{
// 2^31 = 0x80000000
// 2^31-1 = 0x7fffffff
int y = (MT[i] & 0x80000000) + (MT[(i+1) % 624] & 0x7fffffff);
MT[i] = MT[(i + 397) % 624] ^ (y >> 1);
if (y & 1)
MT[i] ^= 2567483615;
}
}
輸出函數(shù)
int rand()
{
if(!isInit)
srand((int)time(NULL));
if(index == 0)
generate();
int y = MT[index];
y = y ^ (y >> 11);
y = y ^ ((y << 7) & 2636928640);
y = y ^ ((y << 15) & 4022730752);
y = y ^ (y >> 18);
index = (index + 1) % 624;
return y; //筆者注:y即為產(chǎn)生的隨機(jī)數(shù)
}
int main()
{
srand(0); //設(shè)置隨機(jī)種子
int cnt = 0;
for(int i=0; i<1000000; i++) //下面的循環(huán)是用來判斷隨機(jī)數(shù)的奇偶概率的
{
if(rand() & 1)
cnt++;
}
cout<<cnt / 10000.0<<'%'<<endl;
return 0;
}
->continue
這里回答一下前面的那個問題:
為什么循環(huán)節(jié)是2^n-1而不是2^n
這個問題的答案和為什么初始序列不能是 { 0 , 0 , 0 , 0 }是一樣的,因?yàn)槿绻?的話,無論怎么異或運(yùn)算都不能產(chǎn)生循環(huán)。那么還怎么偽隨機(jī)啊。
因?yàn)椴荒苁侨?,所以循環(huán)節(jié)要-1
最后非常感謝你能有耐心讀到這里。
本文到這里應(yīng)該就水完結(jié)束了,當(dāng)然,既然你好不容易看到了這里,我就給一個彩蛋吧( 有點(diǎn)勉強(qiáng) )。
關(guān)于rand函數(shù)為什么是用1103515245和12345這兩個數(shù)…你可以理解為玄學(xué)。不過真是原因是用這兩個數(shù)推算出來的的隨機(jī)數(shù)分布相對平均。更符合偽隨機(jī)數(shù)的特性。( 這個我盡力用實(shí)驗(yàn)來論證,目前還在構(gòu)思,也可能正在實(shí)驗(yàn) )