乱数生成関数の差異

2014. 06. 04
詳細! Objective-C iPhoneアプリ開発 入門ノート Xcode5+iOS7対応」を読み始めて、乱数の生成にarc4random()関数を使用していたので、以前使用していたrand()random()関数との違いを調べてみました。


●宣言

rand()、random()、arc4random()、arc4random_uniform()関数は、いずれもstdlib.hで以下のように宣言されています。

int rand(void);

long random(void);

u_int32_t arc4random(void);

u_int32_t arc4random_uniform(u_int32_t /*upper_bound*/)
                __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);

arc4random()とarc4random_uniform()関数は、戻り値がu_int32_t(32bit unsigned int)なので、型変換する際には注意が必要です。
(「Qiita/Objective-C/arc4randomの罠」や「だいきちのブログ/気ままにObjective-C/arc4random()でマイナス値が出ることについての考察」参照)


●各関数の差異

乱数発生の内部処理に関しては「和田維作のホームページ/良い乱数・悪い乱数」などを参照していただくとして、実際に利用する立場としてどの関数を使うべきかを考えます。

rand()関数は「Mac OS X Manual Page/srand(3)」で"悪い乱数ジェネレータ(bad random number generator)"であるとしてrandom()関数を使用するように求めています。

random()関数は「Mac OS X Manual Page/random(3)」で"良い乱数ジェネレータ(better random number generator)"としていますが、rand()と同様にそのままでは再現性を有するという欠点があり、暗号化品質を求めるならばarc4random()を使用するよう推奨されています。

ただしrand()はsrand()、random()はsrandom()関数でシード値を与えることで再現性を回避することはできます。

arc4random()関数は、rand()やrandom()の2倍の範囲を持つARC4(「Wikipedia/RC4」参照)由来の乱数ジェネレータですが、上限が2のべき乗でない場合にモジュロバイアスが発生するという欠点があります。

例えば0から(2のべき乗でない)9までの乱数を求めようとすると、出現する値が偏在してしまうという問題があります。
(「Learn iPhone, iOS, Objective-c, cocos2dx, Unity and ....?/Objective-C - arc4random()が生成する乱数の偏りについて」参照)

arc4random_uniform()関数は、arc4random()のモジュロバイアス問題を解決しているので推奨されています。

またarc4random_uniform()はシード値を与える必要も無いので、(Mac OS X 10.7またはiOS 4.3以降であれば)通常はarc4random_uniform()を使うと良いでしょう。


●各関数の正規分布

実際に各関数を実行した結果が気になるところですので試してみます。

テスト環境)
・iMac 21.5" Late 2013(OS X 10.9.3)
・Xcode 5.1.1
・iOS シミュレータ ver.7.1(iPhone Retina 4inch 64bit)

※実機テストではないのでご注意ください。

各関数で0〜9の乱数を100,000個発生し、0〜9の各整数についての標準偏差を計算しました。
(標準偏差については「経済指標のかんどころ/第14章 統計/平均と標準偏差」を参照)

rand()関数の標準偏差

// 生成する乱数の数と乱数の範囲の設定
const int sampleNumber = 100000;    // 標本数
const int rangeNumber = 10;              // 乱数上限

// 乱数を収納する可変配列の作成
NSMutableArray *randArray = [NSMutableArray array];

// 乱数を生成し、可変配列へ収納
for (int i = 0; i < sampleNumber; i++) {
    randArray[i] = @(rand() % rangeNumber);    // 乱数生成
}

// 分散と標準偏差用の変数の初期化
double randSum = 0, randSD = 0;

for (int j = 0; j < rangeNumber; j++) {
    // 抽出用に可変配列をコピー
    NSMutableArray *randArrayCopy = [NSMutableArray arrayWithArray:randArray];
    // 抽出条件の設定
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K == %d", @"self", j];
    // コピーした可変配列から特定の整数を持つ要素を抽出
    [randArrayCopy filterUsingPredicate:pred];
    // 抽出した要素数から平均個数を引いて偏差を求め、2乗して求めた分散を順次加算
    randSum += pow(abs((int)randArrayCopy.count - sampleNumber / rangeNumber), 2);
}

// 集計した分散を標本数で割り、平方根を取って標準偏差を求める
randSD = sqrt(randSum / rangeNumber);

// 標準偏差の出力
NSLog(@"randSD = %f", randSD);

他の関数は乱数生成の行以外は同様です。
rand()とrandom()に関してはsrand()およびsrandom()でシードを与えた場合も試しました。
(シードは最初の可変配列を作る前に作成しています。)

// rand() + srand()標準偏差
srand((unsigned int)time(NULL));

// random()標準偏差
randomArray[i] = @(random() % rangeNumber);

// random() + srandom()標準偏差
srandom((unsigned int)time(NULL));

// arc4random()標準偏差
arc4randomArray[i] = @(arc4random() % rangeNumber);

// arc4random_uniform()標準偏差
arc4random_uniformArray[i] = @(arc4random_uniform(rangeNumber));

10回試行した結果を下表に示します。

試行回数rand()rand() +
srand()
random()random() +
srandom()
arc4random()arc4random
_uniform()
1138.35169.597100.77965.41787.782103.105
2138.35188.729100.779112.28494.74958.579
3138.35192.961100.77987.45898.28882.492
4138.35186.401100.779121.59867.549105.556
5138.351130.972100.779121.43898.821165.072
6138.351105.360100.77955.88776.107138.548
7138.35194.855100.779123.53282.932103.739
8138.35193.039100.77958.762112.18069.430
9138.351117.240100.779138.66264.48296.635
10138.35186.202100.77979.577147.49398.373
算術平均138.35196.536100.77996.461593.038102.153

こうして見るとrand()とrandom()に関しては再現性があり、シードを与えることでそれを回避できるとともに分散が減少することが分かります。
しかしモジュロバイアスを回避しているはずのarc4random_uniform()の方が、arc4random()より分散が増大していることも分かります。

納得できなかったので標本数を1,000,000個にして試しました。

試行回数rand()rand() +
srand()
random()random() +
srandom()
arc4random()arc4random
_uniform()
1336.788195.484212.112375.150294.668324.041
2336.788265.282212.112171.093306.084287.701
3336.788267.296212.112282.826258.322223.949
4336.788342.466212.112205.370317.153290.070
5336.788163.419212.112288.707254.005204.910
6336.788269.651212.112169.555254.979433.367
7336.788469.068212.112360.910404.388242.687
8336.788379.788212.112293.812288.210270.242
9336.788383.043212.112156.895302.076243.467
10336.788386.001212.112120.170289.877224.977
算術平均336.788312.150212.112242.449296.976274.541

arc4random_uniform()がarc4random()に比べて若干減少したものの、今度はただのrandom()よりシードを与えたrandom()が上回るとともに、arc4random()とarc4random_uniform()がrandom()よりも上回る結果となりました。

この結果が試行回数が少ないせいか、他の条件が悪いせいなのか、環境に依るものかは分かりません。
(プログラムではrand() → rand() + srand() → ・・・ → arc4random_uniform()と一連で実行しているので、その影響があるかもしれません。それぞれ単体で実行した場合と結果が異なるかと思います。)

ですがrand()は非推奨であり、random()も再現性を伴うため使用するのが憚れますし、arc4random_uniform()がモジュロバイアスを回避するものと明言されている以上、今回の試行結果から使用を躊躇する理由にはならないでしょう。

一先ず現状ではiOS 4.3以降をターゲットにしているならば、arc4random_uniform()を使用することを勧めます。



参考文献

Mac OS X Manual Page/srand(3)

Mac OS X Manual Page/random(3)

Mac OS X Manual Page/arc4random(3)

Mac OS X Manual Page/arc4random_uniform(3)

Qiita/Objective-C/arc4randomの罠

だいきちのブログ/気ままにObjective-C/arc4random()でマイナス値が出ることについての考察

和田維作のホームページ/良い乱数・悪い乱数

Wikipedia/RC4

Learn iPhone, iOS, Objective-c, cocos2dx, Unity and ....?/Objective-C - arc4random()が生成する乱数の偏りについて

経済指標のかんどころ/第14章 統計/平均と標準偏差

詳細! Objective-C iPhoneアプリ開発 入門ノート Xcode5+iOS7対応詳細! Objective-C iPhoneアプリ開発 入門ノート Xcode5+iOS7対応
(2013/11/02)
大重 美幸

商品詳細を見る






bose_soundlink_revolve
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
03 | 2017/04 | 05
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

bose_soundlink_revolve
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR