Objective-C에서 난수 생성


741

나는 주로 Java 헤드이고 0에서 74 사이의 의사 난수를 생성하는 방법을 원합니다. Java에서는 다음 방법을 사용합니다.

Random.nextInt(74)

나는 씨앗이나 진정한 무작위성에 대한 토론에 관심이 없으며 Objective-C에서 동일한 작업을 수행하는 방법에 대해서만 이야기합니다. Google을 sc이 뒤졌으며, 상이하고 상충되는 정보가 많이있는 것 같습니다.

답변:


1025

arc4random_uniform()기능을 사용해야합니다 . 에 우수한 알고리즘을 사용합니다 rand. 씨앗을 설정할 필요조차 없습니다.

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

arc4random매뉴얼 페이지

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

4
NB : 열악한 범위를 선택하면 arc4random의 분포가 매우 열악 할 수 있습니다. 나는 2의 힘을 기대하지 못했습니다. @ yood 's version +1 사용-큰 숫자 (예 : 400의 범위)에 대해 눈에 띄는 차이를
Adam

32 비트 숫자 만 생성합니까?
jjxtra

4
@codecowboy 그렇지 않습니다. 항상 [0, (2 ^ 32) -1] 범위의 정수를 반환합니다. 범위의 상한을 지정한 숫자로 제한하는 것은 모듈로입니다.
Motasim

1
이것이 0에서 73 사이의 임의의 숫자를 제공하지 않습니까?
톰 하워드

424

arc4random_uniform(upper_bound)함수를 사용하여 범위 내에서 난수를 생성 하십시오 . 다음은 0에서 73 사이의 숫자를 생성합니다.

arc4random_uniform(74)

arc4random_uniform(upper_bound)매뉴얼 페이지에 설명 된대로 모듈로 바이어스 를 방지 합니다.

arc4random_uniform ()은 upper_bound보다 작은 균일하게 분포 된 난수를 반환합니다. arc4random_uniform ()은``arc4random () % upper_bound ''와 같은 구성보다 권장 됩니다. 상한이 2의 거듭 제곱이 아닌 경우 " 모듈러스 바이어스 "를 피하기 때문입니다.


32
arc4random_uniform ()에는 iOS 4.3이 필요합니다. 구형 장치를 지원하는 경우 검사를 추가해야합니다. 검사에 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_3 실패하면 다른 솔루션으로 넘어갑니다.
Ron

6
arc4random_uniform ()에도 10.7 이상이 필요합니다. 10.6에서 앱 충돌
Tibidabo

@Tibidabo 귀하의 의견은 매우 거짓이며 오해의 소지가 있습니다. iOS 10.3에서 arc4random_uniform () 사용에 지쳤으며 아무런 문제가 없습니다. 그것은 나중에 10.7을 필요로하지 않습니다
넷째

1
@Fourth iOS 10.7과 같은 것은 없으며 macOS 10.7입니다. 내가 당시 최대 iOS 5라는 의견을 쓴 지 5 년이 넘었습니다.
Tibidabo

63

C와 똑같이

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

(0을 포함하지만 74는 제외한다고 가정하면 Java 예제와 동일합니다)

편집 : Feel로 대체 할 무료 random()arc4random()에 대한 rand()(다른 사람들이 지적으로,이다, 매우 짜증나).


43
-1. 난수 생성기를 시드해야합니다. 그렇지 않으면 각 실행에서 동일한 숫자 패턴을 얻게됩니다.
Alex Reynolds

0과 다른 숫자로 시작하고 싶습니까?
amok

2
@ amok : 당신은 당신이 결과에 시작하려는 숫자를 추가 할 수 있습니다
Florin

2
나는 숫자 9를 계속
받는다

난 그냥) (랜덤 테스트, 그리고 랜드와 같은 문제를 ()했다
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의 보수를 사용하는 이진 정수로 고정되어 있어도 정식입니다. 따라서 최대-최소 + 1은 최대 + 1-최소 및 1 + 최대-최소와 정확히 동일합니다.
Michael Morris

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

죄송합니다. 요점을 모르겠습니다. 배정 밀도가 필요한 경우 "float"를 "double"로 쉽게 대체 할 수 있습니다.
Tibidabo

나는 그것이 큰 문제라고 생각하지 않습니다. 정수만 필요한 경우 float / double 변환을 제거하여 arc4random () / 0x100000000) * (high_bound-low_bound) + low_bound를 사용할 수 있습니다.
티비 다보

이 방법으로 정수를 부동 소수점으로 변환하면 바이어스가 발생합니다. drand48부동 소수점에 대신 사용하십시오 .
Franklin Yu

37

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보다 0을 얻을 가능성이 두 배입니다.


7
시간을 srandom ()에 전달하는 대신 srandomdev ()를 호출 할 수도 있습니다. 쉽고 수학적으로 더 좋습니다.
benzado

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 당신은 당신의 downvote를 정정 할 수 있습니다].
AW101

objective-c는 objc 메소드에 후기 바인딩을 사용하지만 C 함수의 경우에는 그렇지 않습니다. 함수가 런타임에 존재하지 않으면이 코드는 확실히 중단됩니다.
Richard J. Ross III

8
Apple에 따르면 "... 링커는 사용할 수없는 함수의 주소를 NULL로 설정합니다 ...", 목록 3.2 : developer.apple.com/library/mac/#documentation/DeveloperTools/…를 참조하십시오 . 좋아, 약하게 연결되어 있어야하지만 충돌하지는 않습니다.
AW101

1
함수의 주소가 NULL인지 확인하는 것은 MacOS X 및 iOS 모두에서 모든 버전의 C, C ++ 및 Objective-C에서 사용 된 방법입니다.
gnasher729

14

Java에서 Math.random ()과 같은 기능을 수행 할 수 있도록 난수 유틸리티 클래스를 작성했습니다. 그것은 두 가지 기능을 가지고 있으며 모두 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

7

훌륭한 명료 한 답변이 이미 있지만 질문은 0에서 74 사이의 임의의 숫자를 요구합니다. 사용 :

arc4random_uniform(75)


4

iOS 9 및 OS X 10.11부터 새로운 GameplayKit 클래스를 사용하여 다양한 방법으로 난수를 생성 할 수 있습니다.

선택할 수있는 네 가지 소스 유형이 있습니다 : 일반 무작위 소스 (이름이없는 시스템, 그 아래에있는 것을 선택하는 시스템), 선형 합동, 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

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.