Objective-Cでの乱数の生成


741

私は主にJavaの頭であり、0〜74の疑似乱数を生成する方法が必要です。Javaでは、次のメソッドを使用します。

Random.nextInt(74)

シードや真のランダム性についての議論には興味がありません。Objective-Cで同じタスクをどのように達成するかだけです。私はグーグルを精査しました、そして多くの異なったそして矛盾する情報のビットがあるようです。

回答:


1025

arc4random_uniform()関数を使用する必要があります。それはに優れたアルゴリズムを使用しrandます。シードを設定する必要すらありません。

#include <stdlib.h>
// ...
// ...
int r = arc4random_uniform(74);

arc4randommanページ:

NAME
     arc4random, arc4random_stir, arc4random_addrandom -- arc4 random number generator

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <stdlib.h>

     u_int32_t
     arc4random(void);

     void
     arc4random_stir(void);

     void
     arc4random_addrandom(unsigned char *dat, int datlen);

DESCRIPTION
     The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8
     bit S-Boxes.  The S-Boxes can be in about (2**1700) states.  The arc4random() function returns pseudo-
     random numbers in the range of 0 to (2**32)-1, and therefore has twice the range of rand(3) and
     random(3).

     The arc4random_stir() function reads data from /dev/urandom and uses it to permute the S-Boxes via
     arc4random_addrandom().

     There is no need to call arc4random_stir() before using arc4random(), since arc4random() automatically
     initializes itself.

EXAMPLES
     The following produces a drop-in replacement for the traditional rand() and random() functions using
     arc4random():

           #define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))

96
arc4random_uniform(x)@yoodによる以下の説明に従って使用してください。これはstdlib.h(OS X 10.7およびiOS 4.3以降)にもあり、乱数のより均一な分布を提供します。使用法int r = arc4random_uniform(74);
LavaSlider 2012年

4
注意:たまたま悪い範囲を選択した場合、arc4randomからの分布は非常に悪くなる可能性があります。2のべき乗の期待に気づかなかった。@yoodのバージョンで使用するための+1-より大きな数(たとえば、400の範囲)で顕著な違いがありました
Adam

32ビットの数値のみを生成しますか?
jjxtra

4
@codecowboyありません。常に[0、(2 ^ 32)-1]の範囲の整数を返します。範囲の上限を指定した数に制限するのはモジュロです。
モタシム2013年

1
これは0から73までの乱数を与えませんか?
トムハワード

424

arc4random_uniform(upper_bound)関数を使用して、範囲内の乱数を生成します。以下は、0から73までの数値を生成します。

arc4random_uniform(74)

arc4random_uniform(upper_bound)manページで説明されているように、モジュロバイアスを回避します。

arc4random_uniform()は、upper_boundより小さい均一に分布した乱数を返します。上限が2のべき乗でない場合に「モジュロバイアス」を回避するため、「arc4random()%upper_bound」のような構成よりもarc4random_uniform()をお勧めします。


32
arc4random_uniform()にはiOS 4.3が必要です。古いデバイスをサポートしている場合は、チェックを追加する必要#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_3 があります。チェックに失敗した場合は、別のソリューションにフォールバックしてください。
Ron

6
arc4random_uniform()にも10.7以降が必要です。10.6でアプリがクラッシュします
Tibidabo、2013年

@Tibidaboあなたのコメントは非常に虚偽で誤解を招くものです。iOS 10.3でarc4random_uniform()を使用しただけで、問題はありません。これは、10.7以降が必要としない
第四

1
@フォースiOS 10.7のようなものはありません、それはmacOS 10.7です。私がコメントを書いてから5年以上経ちましたが、当時は最大のiOS 5でした。
Tibidabo 2017年

63

Cと同じように

#include <time.h>
#include <stdlib.h>
...
srand(time(NULL));
int r = rand() % 74;

(あなたがあなたのJavaの例がすることである0を含むが74を除くことを意味すると仮定して)

編集:フィールを代用して自由random()またはarc4random()のためにrand()(他の人が指摘したように、ある、かなり嫌)。


43
-1。乱数ジェネレータをシードする必要があります。そうしないと、実行するたびに同じパターンの数値が得られます。
Alex Reynolds、

ゼロ以外の数値から始めたいのですが?
amok

2
@amok:開始する数値を結果に追加するだけです
Florin

2
私は番号9を取得し続けます。かなりランダムです; D
alexyorke 2010

random()をテストしたところ、rand()と同じ問題が発生しました
LolaRun

50

多くのプロジェクトで使用する方法を追加できると思いました。

- (NSInteger)randomValueBetween:(NSInteger)min and:(NSInteger)max {
    return (NSInteger)(min + arc4random_uniform(max - min + 1));
}

多くのファイルでそれを使用してしまう場合、通常は次のようにマクロを宣言します。

#define RAND_FROM_TO(min, max) (min + arc4random_uniform(max - min + 1))

例えば

NSInteger myInteger = RAND_FROM_TO(0, 74) // 0, 1, 2,..., 73, 74

注:iOS 4.3 / OS X v10.7(Lion)以降のみ


2の補数を使用する2進整数で固定されていても、加算は可換です。そのため、max-min + 1は、max + 1-minおよび1 + max-minとまったく同じです。
マイケルモリス14

44

これにより、0〜47の浮動小数点数が得られます。

float low_bound = 0;      
float high_bound = 47;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

または単に

float rndValue = (((float)arc4random()/0x100000000)*47);

下限と上限の両方が負になることもあります。以下のサンプルコードは、-35.76から+12.09の間の乱数を提供します。

float low_bound = -35.76;      
float high_bound = 12.09;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

結果を丸め整数値に変換します。

int intRndValue = (int)(rndValue + 0.5);

これは悪いです。doubleではなく、floatを使用するのはなぜですか?そして、浮動小数点値が0から47の場合、(int)(rndValue + 0.5)は0.0から0.5から0への値のみを変換しますが、0.5から1.5への値は1に変換されます。したがって、0と47は他のすべての数の半分の頻度でしか出現しません。
gnasher729 14

@ gnasher729申し訳ありませんが、あなたの意見はわかりません。明らかに倍精度が必要な場合は、「float」を「double」に簡単に置き換えることができます
Tibidabo

大したことではないと思います。整数のみが必要な場合は、float / double変換を削除して、arc4random()/ 0x100000000)*(high_bound-low_bound)+ low_boundを使用できます。
ティビダボ2014年

この方法で整数を浮動小数点に変換すると、バイアスが発生します。drand48浮動小数点の代わりに使用してください。
フランクリンユー

37

rand(3)のマニュアルページによると、rand(3)関数のrandファミリは、random(3)によって廃止されました。これは、rand()の下位12ビットが循環パターンを通過するためです。乱数を取得するには、符号なしシードでsrandom()を呼び出してジェネレータをシードし、次にrandom()を呼び出します。したがって、上記のコードと同等のものは

#import <stdlib.h>
#import <time.h>

srandom(time(NULL));
random() % 74;

シードを変更したくない場合を除いて、プログラムで一度だけsrandom()を呼び出す必要があります。真にランダムな値については説明したくないとおっしゃいましたが、rand()はかなり悪い乱数ジェネレータであり、random()は0とRAND_MAXの間の数を生成するため、依然としてモジュロバイアスの影響を受けます。したがって、たとえばRAND_MAXが3で、0と2の間の乱数が必要な場合、1や2よりも2倍の確率で0を取得します。


7
srandom()に時間を渡す代わりに、srandomdev()を呼び出すこともできます。それは同じくらい簡単で数学的に優れています。
ベンザド2009

31

使いやすい arc4random_uniform。ただし、これはiOS 4.3以下では使用できません。幸い、iOSはこのシンボルをコンパイル時ではなく実行時にバインドします(そのため、#ifプリプロセッサディレクティブを使用して、それが使用可能かどうかを確認しないでください)。

arc4random_uniform利用可能かどうかを判断する最良の方法は、次のようなことです。

#include <stdlib.h>

int r = 0;
if (arc4random_uniform != NULL)
    r = arc4random_uniform (74);
else
    r = (arc4random() % 74);

9
この質問は、遅延バインディングを使用するObjective-Cに関するものです。コンパイル/リンク時にバインドするCとは異なり、Objective-Cは実行時にシンボルをバインドし、バインドできないシンボルはNULLに設定されます。これは有効なCではないことは正しいですが、最も確実にObjective-Cです。私はこの正確なコードをiPhoneアプリで使用しています。[ps投票を訂正してください]。
AW101 2012

Objective-Cはobjcメソッドにレイトバインディングを使用しますが、C関数の場合はそうではありません。実行時に関数が存在しない場合、このコードは確実にクラッシュします。
リチャードJ.ロスIII

8
Appleによれば、「...リンカーは使用できない関数のアドレスをNULLに設定します...」とリスト3.2を参照してください:developer.apple.com/library/mac/#documentation/DeveloperTools/…。リンクは弱くする必要がありますが、クラッシュしません。
AW101 2012

1
関数のアドレスがNULLであることを確認することは、MacOS XとiOSの両方のC、C ++、およびObjective-Cのすべてのバージョンで使用されている方法です。
gnasher729 14

14

私は、JavaでMath.random()のように機能するものを作成するために、独自の乱数ユーティリティクラスを作成しました。機能は2つだけで、すべてCで作成されています。

ヘッダーファイル:

//Random.h
void initRandomSeed(long firstSeed);
float nextRandomFloat();

実装ファイル:

//Random.m
static unsigned long seed;

void initRandomSeed(long firstSeed)
{ 
    seed = firstSeed;
}

float nextRandomFloat()
{
    return (((seed= 1664525*seed + 1013904223)>>16) / (float)0x10000);
}

これは、疑似ランダムを生成するかなり古典的な方法です。私のアプリデリゲートで私は電話します:

#import "Random.h"

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    initRandomSeed( (long) [[NSDate date] timeIntervalSince1970] );
    //Do other initialization junk.
}

その後、私はただ言う:

float myRandomNumber = nextRandomFloat() * 74;

このメソッドは0.0f(両端を含む)〜1.0f(両端を含まない)の乱数を返すことに注意してください。


3
1.ランダムに作成された乱数関数は通常、あまりランダムではありません。2. 64ビットプロセッサでは完全に機能しません。3. 1970年からの秒数をランダムシードとして使用すると、数値が予測可能になります。
gnasher729 14

7

すばらしい明確な答えはすでにいくつかありますが、質問では0〜74の乱数を求めます。使用:

arc4random_uniform(75)


4

iOS 9およびOS X 10.11では、新しいGameplayKitクラスを使用して、さまざまな方法で乱数を生成できます。

選択できるソースタイプは4つあります。一般的なランダムソース(名前なし、システムが何をするかを選択する)、線形合同、ARC4、およびMersenne Twisterです。これらはランダムな整数、浮動小数点数、ブール値を生成できます。

最も単純なレベルでは、次のようにシステムの組み込みランダムソースから乱数を生成できます。

NSInteger rand = [[GKRandomSource sharedRandom] nextInt];

-2,147,483,648〜2,147,483,647の数値が生成されます。0と上限(排他的)の間の数値が必要な場合は、次のようにします。

NSInteger rand6 = [[GKRandomSource sharedRandom] nextIntWithUpperBound:6];

GameplayKitには、サイコロを操作するための便利なコンストラクタがいくつか組み込まれています。たとえば、次のように6面のサイコロを振ることができます。

GKRandomDistribution *d6 = [GKRandomDistribution d6];
[d6 nextInt];

さらに、などを使用してランダム分布を形成できますGKShuffledDistribution


Mersenneは最も速く、生成された乱数の品質が通常あまり重要ではないゲーム開発などに最適です。
Robert Wasmann 2016

3

0から99までの乱数を生成します。

int x = arc4random()%100;

500〜1000の乱数を生成します。

int x = (arc4random()%501) + 500;

1

//次の例では、0〜73の数値を生成します。

int value;
value = (arc4random() % 74);
NSLog(@"random number: %i ", value);

//In order to generate 1 to 73, do the following:
int value1;
value1 = (arc4random() % 73) + 1;
NSLog(@"random number step 2: %i ", value1);

出力:

  • 乱数:72

  • 乱数ステップ2:52


1

ゲーム開発者にとっては、random()を使用してランダムを生成します。おそらく、arc4random()を使用するよりも少なくとも5倍高速です。random()の全範囲を使用してランダムを生成する場合、モジュロバイアスは特にゲームでは問題になりません。必ず最初にシードしてください。AppDelegateでsrandomdev()を呼び出します。ここにいくつかのヘルパー関数があります:

static inline int random_range(int low, int high){ return (random()%(high-low+1))+low;}
static inline CGFloat frandom(){ return (CGFloat)random()/UINT32_C(0x7FFFFFFF);}
static inline CGFloat frandom_range(CGFloat low, CGFloat high){ return (high-low)*frandom()+low;}

random()はそれほどランダムではないことに注意してください。コードで速度が重要でない場合(時々使用される場合など)は、arc4random()を使用します。
Robert Wasmann 16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.