이것은 이전에 게시 된 질문의 후속입니다.
주사위의 측면을 모방하기 위해 1 ~ 6과 같은 특정 범위 내에서 임의의 숫자를 생성 할 수 있기를 바랍니다.
어떻게하면 되나요?
답변
지금까지의 모든 답은 수학적으로 잘못되었습니다. 반환 하는 구간의 길이를 나누지 않는 한 (즉, 2의 거듭 제곱) 반환 rand() % N
은 범위 내의 숫자를 균일하게 제공하지 않습니다 . 또한의 모듈 리가 독립적 인지 여부를 알지 못합니다. 균일하지만 매우 무작위 적이 지 않은. 합리적으로 보이는 유일한 가정 은 포아송 분포를내는 것입니다. 같은 크기의 겹치지 않는 두 부분 구간은 똑같이 가능성이 있고 독립적입니다. 유한 한 값 집합의 경우 이는 균일 한 분포를 의미하며의 값 이 잘 분산되도록합니다.[0, N)
N
rand()
rand()
0, 1, 2, ...
rand()
rand()
즉, 범위를 변경하는 유일한 올바른 방법은 rand()
상자로 나누는 것입니다. 예를 들어 RAND_MAX == 11
범위를 원하는 경우 1, 2 등으로 1..6
할당해야합니다 . 이들은 분리되고 동일한 크기의 간격이므로 균일하고 독립적으로 분포됩니다.{0,1}
{2,3}
부동 소수점 나누기를 사용하라는 제안은 수학적으로 타당하지만 원칙적으로 반올림 문제가 있습니다. 아마도 double
그것을 작동시키기에 충분히 높은 정밀도 일 것입니다. 아마 아닐거야. 나는 모르고 그것을 알아 내고 싶지도 않다. 어쨌든 대답은 시스템에 따라 다릅니다.
올바른 방법은 정수 산술을 사용하는 것입니다. 즉, 다음과 같은 것을 원합니다.
#include <stdlib.h> // For random(), RAND_MAX
// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
unsigned long
// max <= RAND_MAX < ULONG_MAX, so this is okay.
num_bins = (unsigned long) max + 1,
num_rand = (unsigned long) RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
long x;
do {
x = random();
}
// This is carefully written not to overflow
while (num_rand - defect <= (unsigned long)x);
// Truncated division is intentional
return x/bin_size;
}
루프는 완벽하게 균일 한 분포를 얻기 위해 필요합니다. 예를 들어, 0에서 2까지의 임의의 숫자가 주어지고 0에서 1까지의 숫자 만 원하면 2를 얻지 못할 때까지 계속 당기십시오. 이것이 동일한 확률로 0 또는 1을 제공하는지 확인하는 것은 어렵지 않습니다. 이 방법은 다르게 코딩되었지만 nos가 대답 한 링크에도 설명되어 있습니다. 나는 더 나은 배포판을 가지고 random()
있기보다는 rand()
(에 대한 man 페이지에서 언급했듯이 rand()
) 사용하고 있습니다.
기본 범위를 벗어난 임의의 값을 얻으려면 [0, RAND_MAX]
까다로운 작업을 수행해야합니다. 아마도 가장 편리한 함수를 정의하는 것입니다 random_extended()
끌어 n
비트 (사용 random_at_most()
으로) 되돌아 [0, 2**n)
한 다음 적용 random_at_most()
과 random_extended()
대신에 random()
(그리고 2**n - 1
대신에 RAND_MAX
) 이하의 임의의 값을 뽑아 2**n
당신이 그런를 보유 할 수있는 숫자 유형이 가정, 가치. 마지막으로, 물론 음수 값을 포함 [min, max]
하여를 사용하여 값을 얻을 수 있습니다 min + random_at_most(max - min)
.
답변
@Ryan Reich의 답변에 이어 정리 된 버전을 제공 할 것이라고 생각했습니다. 첫 번째 경계 검사는 두 번째 경계 검사를 고려할 때 필요하지 않으며 재귀 적이 아닌 반복적으로 만들었습니다. [최소, 최대] 범위의 값을 반환합니다 . 여기서 max >= min
및 1+max-min < RAND_MAX
.
unsigned int rand_interval(unsigned int min, unsigned int max)
{
int r;
const unsigned int range = 1 + max - min;
const unsigned int buckets = RAND_MAX / range;
const unsigned int limit = buckets * range;
/* Create equal size buckets all in a row, then fire randomly towards
* the buckets until you land in one of them. All buckets are equally
* likely. If you land off the end of the line of buckets, try again. */
do
{
r = rand();
} while (r >= limit);
return min + (r / buckets);
}
답변
다음은 범위의 최대 값과 최소값을 알고 있고 범위 사이에 포함 된 숫자를 생성하려는 경우 공식입니다.
r = (rand() % (max + 1 - min)) + min
답변
unsigned int
randr(unsigned int min, unsigned int max)
{
double scaled = (double)rand()/RAND_MAX;
return (max - min +1)*scaled + min;
}
답변
그냥하지 않겠습니까?
srand(time(NULL));
int r = ( rand() % 6 ) + 1;
%
모듈러스 연산자입니다. 기본적으로 6으로 나누고 나머지를 반환합니다 … from 0-5
답변
편향 문제를 이해하고 있지만 거부 기반 방법의 예측할 수없는 런타임을 견딜 수없는 사람들을 위해이 시리즈는 [0, n-1]
간격 에서 점차적으로 편향된 임의의 정수를 생성 합니다.
r = n / 2;
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
...
고정 소수점 임의의 i * log_2(RAND_MAX + 1)
비트 수 ( i
반복 횟수) 를 합성하고에 의해 긴 곱셈을 수행하여이를 수행합니다 n
.
에 비해 비트 수가 충분히 크면 n
바이어스가 헤아릴 수 없을 정도로 작아집니다.
이 질문 에서와 같이 RAND_MAX + 1
이보다 작은 지 n
( 이 질문 에서와 같이 ) 또는 2의 거듭 제곱 이 아닌지 여부 는 중요하지 않지만 RAND_MAX * n
큰 경우 정수 오버플로를 방지하려면주의해야합니다 .
답변
모듈로 편향을 피하기 위해 (다른 답변에서 제 안됨) 항상 다음을 사용할 수 있습니다.
arc4random_uniform(MAX-MIN)+MIN
여기서 “MAX”는 상한이고 “MIN”은 하한입니다. 예를 들어 10에서 20 사이의 숫자의 경우 :
arc4random_uniform(20-10)+10
arc4random_uniform(10)+10
간단한 솔루션이며 “rand () % N”을 사용하는 것보다 낫습니다.