首先我們先來看下頭各自所屬文件的聲明
uint32_t arc4random(void);
int rand(void) __swift_unavailable("Use arc4random instead.");
long random(void) __swift_unavailable("Use arc4random instead.");
可以看出arc4random()、random()、rand()函數(shù)返回類型分別為uint32_t,int,long,現(xiàn)在的iOS硬件設(shè)備幾乎都是64位,由于C語言生成的隨機(jī)數(shù)為無符號數(shù),即都是正的,我們可以得出隨機(jī)數(shù)取值范圍。
| 函數(shù)名 | 返回值 | 取值范圍 |
|---|---|---|
| rand() | int | 0~2147483647 |
| random() | long | 0~2147483647 |
| arc4random() | uint32_t | 0~4294967295 |
#define RAND_MAX 0x7fffffff,RAND_MAX的值16進(jìn)制0x7ffffff轉(zhuǎn)換為10進(jìn)制為2147483647。
可以得出取值范圍arc4random() > (rand() = random())
下面我們來看一段代碼:
for (int i = 0; i < 5; i ++) {
NSLog(@"%@ - %@ - %@",@(random()),@(random()),@(arc4random()));
}
我們連續(xù)運(yùn)行幾次得到結(jié)果如下:
第一次:
1804289383 - 846930886 - 1208611301
1681692777 - 1714636915 - 3355735759
1957747793 - 424238335 - 2781113645
719885386 - 1649760492 - 1801593043
596516649 - 1189641421 - 460884511
第二次:
1804289383 - 846930886 - 1119699280
1681692777 - 1714636915 - 3441628103
1957747793 - 424238335 - 3443635443
719885386 - 1649760492 - 3847802969
596516649 - 1189641421 - 3735080216
第三次:
1804289383 - 846930886 - 196821635
1681692777 - 1714636915 - 406729781
1957747793 - 424238335 - 1463174244
719885386 - 1649760492 - 2704772030
596516649 - 1189641421 - 3925712717
···
我們可以發(fā)現(xiàn),每次rand()和random()每次輸出結(jié)果都是一樣的,而arc4random()輸出結(jié)果則是隨機(jī)的。
為什么會(huì)出現(xiàn)這種結(jié)果呢?
回答這個(gè)問題前我們先了解幾個(gè)概念。
- 隨機(jī)數(shù)和偽隨機(jī)數(shù)
真正意義上的隨機(jī)數(shù)(或者隨機(jī)事件)在某次產(chǎn)生過程中是按照實(shí)驗(yàn)過程中表現(xiàn)的分布概率隨機(jī)產(chǎn)生的,其結(jié)果是不可預(yù)測的,是不可見的。
而計(jì)算機(jī)中的隨機(jī)數(shù)并不是真正的隨機(jī)數(shù),而是通過通過隨機(jī)函數(shù)按照一定算法模擬產(chǎn)生的,其結(jié)果是確定可預(yù)見的,所以用計(jì)算機(jī)隨機(jī)函數(shù)所產(chǎn)生的“隨機(jī)數(shù)”并不隨機(jī),是偽隨機(jī)數(shù)。
硬件方法是指采集某一種物理噪聲,經(jīng)過抽樣、量化之后得到的隨機(jī)數(shù)。例如大氣噪聲。此類噪聲是由自然界中的布朗運(yùn)動(dòng)等現(xiàn)象產(chǎn)生的,因此可以看作真正的隨機(jī)數(shù)生成器,只要是通過算法產(chǎn)生的隨機(jī)數(shù)都是偽隨機(jī)數(shù)。通過真實(shí)隨機(jī)事件取得的隨機(jī)數(shù)才是真隨機(jī)數(shù)。
- 隨機(jī)種子(Random Seed)
一種以隨機(jī)數(shù)作為對象的以真隨機(jī)數(shù)(種子)為初始條件的隨機(jī)數(shù)。計(jì)算機(jī)中的隨機(jī)數(shù)都是偽隨機(jī)數(shù),以一個(gè)真隨機(jī)數(shù)(種子)作為初始條件,然后用一定的算法不停迭代產(chǎn)生隨機(jī)數(shù)。通俗來講種子就是個(gè)序號,這個(gè)序號交給一個(gè)數(shù)列管理器,通過這個(gè)序號,你從管理器中取出一個(gè)數(shù)列,這個(gè)數(shù)列就是你通過那個(gè)序號得到的隨機(jī)數(shù)。
理解了這兩個(gè)概念我們可以知道:
如果你種子相同,你生成的數(shù)列肯定是每次一樣的,種子不同,不過讓你看起來覺得每次生成的數(shù)列不一樣罷了。
種子和隨機(jī)數(shù)列是一一對應(yīng)的。{An}=f(x), x 就是種子,F(xiàn)()是算法,{An}是數(shù)列,這個(gè)數(shù)列看上去是隨機(jī)的,這是因?yàn)锳n的通項(xiàng)很復(fù)雜。
種子的選擇有規(guī)律嗎?肯定是有!那么生成的隨機(jī)數(shù)也一定是有規(guī)律的了。既然有規(guī)律,那肯定就是偽隨機(jī)了,因?yàn)槟悴恢婪N子和隨機(jī)數(shù)算法對你來說當(dāng)然就是隨機(jī)數(shù)。
現(xiàn)在我們可以解釋前面那段代碼 rand()和random()每次輸出結(jié)果都是一樣的,而arc4random()輸出結(jié)果則是隨機(jī)的這個(gè)問題了。
產(chǎn)生偽隨機(jī)數(shù)需要隨機(jī)種子和隨機(jī)算法。rand()和random()每次產(chǎn)生的值都是一樣的,那說明它們的隨機(jī)種子每次是一樣,下面我們給rand()和random()一個(gè)隨機(jī)的隨機(jī)種子看下會(huì)有怎樣結(jié)果:
//加入隨機(jī)種子
srandom((unsigned int)time(0));
//產(chǎn)生隨機(jī)數(shù)
for (int i = 0; i < 5; i ++) {
NSLog(@"%@",@(random()%100));
}
/*輸出
第一次8 22 90 91 20
第一次93 84 34 50 50
第一次13 33 22 45 78
*/
其中把rand()函數(shù)換成random()每次輸出結(jié)果也都不同,即得到的偽隨機(jī)數(shù)不同。
arc4random()無論加不加隨機(jī)種子,每次輸出的偽隨機(jī)數(shù)都不同。
我嘗試每次把程序卸載重裝,每次產(chǎn)生的隨機(jī)數(shù)也不一樣。
通過以上我們得出結(jié)論:
對于 rand()和random()隨機(jī)函數(shù),每次安裝程序的時(shí)候系統(tǒng)會(huì)為其設(shè)置一個(gè)固定的隨機(jī)種子,如果不主動(dòng)設(shè)置隨機(jī)種子,每次得到的隨機(jī)數(shù)都將一樣??梢酝ㄟ^srandom((unsigned int)time(0));為其設(shè)置隨機(jī)種子,隨機(jī)種子不同,每次隨機(jī)函數(shù)得到的結(jié)果不同。
對于arc4random(),使用時(shí)候不需要生成隨機(jī)種子,系統(tǒng)已經(jīng)默認(rèn)為其生成了隨機(jī)種子。
通過上面比較,arc4random()不僅取值范圍大而且不需要主動(dòng)設(shè)置隨機(jī)種子,是我們比較理想的計(jì)算隨機(jī)數(shù)的選擇。通過蘋果api
int rand(void) __swift_unavailable("Use arc4random instead.");
long random(void) __swift_unavailable("Use arc4random instead.");
也能看出我們使用arc4random()更為妥當(dāng)。
以上就是本文全部內(nèi)容,如果不當(dāng)之處,還望指正。