전체 범위에서 균일하게 난수 생성


94

지정된 간격 [max; min] 내에서 난수를 생성해야합니다.

또한 난수는 특정 지점에 위치하지 않고 간격에 걸쳐 균일하게 분포해야합니다.

Currenly 나는 다음과 같이 생성하고 있습니다.

for(int i=0; i<6; i++)
{
    DWORD random = rand()%(max-min+1) + min;
}

내 테스트에서 난수는 한 지점 주변에서만 생성됩니다.

Example
min = 3604607;
max = 7654607;

생성 된 난수 :

3631594
3609293
3630000
3628441
3636376
3621404

아래 답변에서 : 좋습니다. RAND_MAX는 32767입니다. 저는 C ++ Windows 플랫폼에 있습니다. 균등 분포로 난수를 생성하는 다른 방법이 있습니까?



1
나는 C ++ rand()가 균일 하다는 것을 전혀 몰랐다 . 어떤 라이브러리를 사용하고 있습니까? cstdlib.h'들 rand(): 균일하지 cplusplus.com/reference/cstdlib/rand
마이크 워렌

3
아니요, rand ()는 균일합니다 (일부 초기 버그 구현 제외). 균일하지 않은 것은 모듈러스 '%'연산자를 사용하여 범위를 제한하는 것입니다. 적절한 해결책 은 stackoverflow.com/questions/2999075/… 를 참조하십시오 . 또는 'arc4random_uniform'을 사용할 수있는 경우 직접 사용할 수도 있습니다.
John Meacham 2013 년

@ Alien01 : "Shoe"( "rand가 나쁜 생각 인 이유"등)의 대답에 대한 허용 된 대답을 변경해 주시겠습니까? 내 대답은 정말 구식이며 그것에 대해 찬성표를 얻을 때마다 누군가가 잘못된 통로를 달리고있는 것처럼 느껴집니다.
peterchen

C ++ 11의 random에 대한 좋은 백서 .
Pupsik

답변:


157

rand 나쁜 생각인가

여기서 얻은 대부분의 답변은 rand함수와 모듈러스 연산자를 사용합니다. 이 방법 은 숫자를 균일하게 생성하지 못할 수 있습니다 (범위와 값에 따라 다릅니다.RAND_MAX ) 권장되지 않습니다.

C ++ 11 및 생성 범위

C ++ 11에서는 여러 다른 옵션이 등장했습니다. 그 중 하나는 범위에서 난수를 생성하는 데 필요한 요구 사항에 매우 적합합니다 std::uniform_int_distribution. 예를 들면 다음과 같습니다.

const int range_from  = 0;
const int range_to    = 10;
std::random_device                  rand_dev;
std::mt19937                        generator(rand_dev());
std::uniform_int_distribution<int>  distr(range_from, range_to);

std::cout << distr(generator) << '\n';

그리고 여기 에 실행 예제가 있습니다.

기타 랜덤 생성기

그만큼 <random>헤더는 베르누이, 포아송 정상을 포함하여 분포의 서로 다른 종류의 무수한 다른 난수 생성기를 제공합니다.

컨테이너를 섞는 방법은 무엇입니까?

이 표준은 std::shuffle다음과 같이 사용할 수있는을 제공 합니다.

std::vector<int> vec = {4, 8, 15, 16, 23, 42};

std::random_device random_dev;
std::mt19937       generator(random_dev());

std::shuffle(vec.begin(), vec.end(), generator);

알고리즘은 선형 복잡성으로 요소를 무작위로 재정렬합니다.

Boost.Random

C ++ 11 + 컴파일러에 액세스 할 수없는 경우 다른 대안은 Boost.Random 을 사용하는 것 입니다. 인터페이스는 C ++ 11 인터페이스와 매우 유사합니다.


24
이 답변은 훨씬 더 현대적이므로주의를 기울이십시오.
gsamaras

이것이 정답입니다. 감사! 그래도 해당 코드의 모든 단계에 대한 자세한 설명을보고 싶습니다. 예 : mt19937유형이란 무엇 입니까?
Apollo

@Apollo 문서에는 "32 비트 Mersenne Twister by Matsumoto and Nishimura, 1998"라고되어 있습니다. 의사 난수를 생성하는 알고리즘이라고 가정하고 있습니다.
Shoe

@Shoe, 주어진 범위에 대해 동일한 순서로 숫자를 생성합니다 1 9 6 2 8 7 1 4 7 7. 프로그램을 실행할 때마다 이것을 무작위 화하는 방법은 무엇입니까?

1
@Richard 대안은 무엇입니까?
Shoe

60

[편집] 경고 : 음주 사용하지 rand()통계, 시뮬레이션, 암호화 또는 심각한 아무것도.

숫자를 보이게 하기에 충분합니다서둘러 평범한 인간에게 무작위로 .

더 나은 옵션에 대해서는 @Jefffrey의 답변 을 참조 하거나 암호 보안 난수에 대해서는 이 답변 을 참조하십시오 .


일반적으로 높은 비트는 낮은 비트보다 더 나은 분포를 보여주기 때문에 간단한 목적으로 범위의 난수를 생성하는 권장 방법은 다음과 같습니다.

((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

참고 : RAND_MAX + 1이 오버플로되지 않는지 확인하십시오 (Demi에게 감사드립니다)!

나누기는 간격 [0, 1]에서 난수를 생성합니다. 이것을 필요한 범위로 "늘립니다". max-min + 1이 RAND_MAX에 가까워 질 때만 Mark Ransom이 게시 한 것과 같은 "BigRand ()"함수가 필요합니다.

이것은 또한 모듈로로 인한 일부 슬라이싱 문제를 방지하여 숫자를 더욱 악화시킬 수 있습니다.


내장 난수 생성기는 통계 시뮬레이션에 필요한 품질을 보장하지 않습니다. 숫자가 사람에게 "무작위로 보이는"것은 괜찮지 만 심각한 응용 프로그램의 경우 더 나은 것을 선택하거나 적어도 그 속성을 확인해야합니다 (일반적으로 균일 한 분포는 좋지만 값은 상관 관계가 있으며 시퀀스는 결정적입니다. ). Knuth는 난수 생성기에 대한 훌륭한 (읽기 어려운 경우) 논문을 가지고 있으며, 최근에 LFSR 이 훌륭하고 구현하기 간단 하다는 것을 발견 했습니다.


4
BigRand는 원하는 범위가 RAND_MAX를 초과하지 않는 경우에도 더 나은 결과를 제공 할 수 있습니다. RAND_MAX가 32767이고 32767 가능한 값을 원하는 경우를 고려하십시오. 32768 개의 난수 중 2 개 (0 포함)가 동일한 출력에 매핑되고 다른 것보다 발생할 가능성이 두 배가됩니다. 이상적인 무작위 속성은 아닙니다!
Mark Ransom

8
(RAND_MAX + 1)은 나쁜 생각입니다. 이것은 롤오버되어 음수 값을 줄 수 있습니다. ((double) RAND_MAX) + 1.0
Demi

4
@peterchen : 나는 데미가 말한 것을 오해했다고 생각합니다. 그녀는 이것을 의미했습니다 : ( rand() / ((double)RAND_MAX+1)) * (max-min+1) + min 단순히 변환을 두 배로 옮기고 문제를 피하십시오.
Mooing Duck 2013-08-01

3
또한 이것은 범위의 하위 32767 값에서 범위에서 균등하게 분포 된 32767 값으로 분포를 변경하고 나머지 4017233 값은이 알고리즘에 의해 선택되지 않습니다.
Mooing Duck 2013-08-01

2
주어진 대답은 1만큼 벗어났습니다. 올바른 방정식은 다음과 같습니다. ((double) rand () / (RAND_MAX + 1.0)) * (max-min) + min "max-min + 1"은 % not *를 사용할 때 사용됩니다. . min = 0, max = 1을하면 이유를 알 수 있습니다. peterchen 또는 @ peter-mortensen이 수정할 수 있습니다.
davepc 2013

17

2015 년 최신 기술에 대한 간략한 개요를 통해 Angry Shoe와 peterchen의 탁월한 답변을 보완하고 싶습니다.

좋은 선택

randutils

randutils라이브러리 (프리젠 테이션) 간단한 인터페이스와 (선언) 강력한 임의의 기능을 제공, 흥미로운 참신입니다. 프로젝트에 대한 종속성을 추가하고 새롭기 때문에 광범위하게 테스트되지 않았다는 단점이 있습니다. 어쨌든, 무료 (MIT 라이센스)이고 헤더 전용이므로 시도해 볼 가치가 있다고 생각합니다.

최소 샘플 : 다이 롤

#include <iostream>
#include "randutils.hpp"
int main() {
    randutils::mt19937_rng rng;
    std::cout << rng.uniform(1,6) << "\n";
}

라이브러리에 관심이 없더라도 웹 사이트 ( http://www.pcg-random.org/ )는 일반적인 난수 생성 주제와 특히 C ++ 라이브러리에 대한 흥미로운 기사를 많이 제공합니다.

Boost.Random

Boost.Random (문서) 영감 라이브러리 C++11<random>, 누구와 공유 많은 인터페이스. 이론적으로는 또한 외부 종속성이기는하지만 Boost현재는 "준 표준"라이브러리의 상태를 가지고 있으며, 그 Random모듈은 양질의 난수 생성을위한 고전적인 선택으로 간주 될 수 있습니다. C++11솔루션 과 관련하여 두 가지 장점이 있습니다.

  • C ++ 03에 대한 컴파일러 지원 만 있으면 더 이식 가능합니다.
  • 그것의 random_device좋은 품질의 파종을 제공하기 위해 사용하는 시스템 고유의 방법

유일한 작은 결점은 모듈 오퍼링 random_device이 헤더 전용이 아니라 컴파일하고 링크해야한다는 것 boost_random입니다.

최소 샘플 : 다이 롤

#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>

int main() {
    boost::random::random_device                  rand_dev;
    boost::random::mt19937                        generator(rand_dev());
    boost::random::uniform_int_distribution<>     distr(1, 6);

    std::cout << distr(generator) << '\n';
}

최소 샘플은 잘 작동하지만 실제 프로그램은 한 쌍의 개선 사항을 사용해야합니다.

  • make mt19937a thread_local: 생성기가 상당히 통통하고 (> 2KB) 스택에 할당되지 않는 것이 좋습니다.
  • mt19937둘 이상의 정수를 가진 시드 : Mersenne Twister는 큰 상태를 가지며 초기화 중에 더 많은 엔트로피의 이점을 누릴 수 있습니다.

별로 좋지 않은 선택

C ++ 11 라이브러리

가장 관용적 인 솔루션이기는하지만 <random>라이브러리는 기본적인 요구 사항에 대해서도 인터페이스의 복잡성에 대한 대가로 많은 것을 제공하지 않습니다. 결함은 다음과 std::random_device같습니다. Standard는 출력에 대해 최소한의 품질을 요구하지 않으며 ( entropy()반환하는 한 0) 2015 년 현재 MinGW (가장 많이 사용되는 컴파일러는 아니지만 심오한 선택이 거의 없음)는 항상 4최소한의 샘플에 인쇄 됩니다.

최소 샘플 : 다이 롤

#include <iostream>
#include <random>
int main() {
    std::random_device                  rand_dev;
    std::mt19937                        generator(rand_dev());
    std::uniform_int_distribution<int>  distr(1, 6);

    std::cout << distr(generator) << '\n';
}

구현이 손상되지 않은 경우이 솔루션은 Boost 솔루션과 동일해야하며 동일한 제안이 적용됩니다.

Godot의 솔루션

최소 샘플 : 다이 롤

#include <iostream>
#include <random>

int main() {
    std::cout << std::randint(1,6);
}

이것은 간단하고 효과적이며 깔끔한 솔루션입니다. 결함 만, 컴파일하는 데 시간이 걸립니다. C ++ 17이 정시에 출시되고 실험 randint기능이 새로운 표준으로 승인 되면 약 2 년이 걸립니다 . 아마도 그때 쯤이면 파종 품질에 대한 보장도 향상 될 것입니다.

나쁜 것이 더 나은 솔루션

최소 샘플 : 다이 롤

#include <cstdlib>
#include <ctime>
#include <iostream>

int main() {
    std::srand(std::time(nullptr));
    std::cout << (std::rand() % 6 + 1);
}

이전 C 솔루션은 유해한 것으로 간주되며 정당한 이유가 있습니다 (여기의 다른 답변 또는 이 자세한 분석 참조 ). 그럼에도 불구하고 장점이 있습니다. 간단하고 휴대 가능하며 빠르고 정직합니다. 즉, 임의의 숫자가 거의 적절하지 않다는 것이 알려져 있으므로 심각한 목적으로 사용하려는 유혹이 없습니다.

회계 트롤 솔루션

최소 샘플 : 다이 롤

#include <iostream>

int main() {
    std::cout << 9;   // http://dilbert.com/strip/2001-10-25
}

9는 일반적인 주사위 굴림에서 다소 특이한 결과이지만, 가장 빠르고 간단하며 가장 캐시 친화적이며 휴대가 간편한이 솔루션의 우수한 품질 조합에 감탄해야합니다. 9를 4로 대체하면 모든 종류의 Dungeons and Dragons 사망에 대한 완벽한 생성기를 얻을 수 있으며, 여전히 기호가 가득한 값 1, 2 및 3을 피할 수 있습니다. 유일한 작은 결점은 Dilbert의 회계 트롤의 나쁜 성질 때문에, 이 프로그램은 실제로 정의되지 않은 동작을 유발합니다.


randutils라이브러리는 이제 PCG라고합니다.
tay10r

10

경우 RAND_MAX32767, 당신은 쉽게 비트의 수를 두배로 할 수있다.

int BigRand()
{
    assert(INT_MAX/(RAND_MAX+1) > RAND_MAX);
    return rand() * (RAND_MAX+1) + rand();
}

나는 이것이 효과가 있다고 생각하지 않는다. 의사 난수 생성기는 일반적으로 결정적입니다. 예를 들어, 첫 번째 경우 rand호출이 반환 0x1234하고 두 번째 0x5678, 당신은 얻을 0x12345678. 다음 숫자는 항상이므로이 숫자는로 시작 하는 유일한 숫자입니다 . 32 비트 결과를 얻지 만 가능한 숫자는 32768입니다. 0x12340x5678
user694733 aug.

@ user694733 좋은 난수 생성기에는 생성 할 수있는 출력 수보다 더 많은 기간이 있으므로 0x1234 다음에 항상 0x5678이 오는 것은 아닙니다.
Mark Ransom

9

가능하다면 Boost를 사용하십시오 . 나는 그들의 무작위 라이브러리에 행운을 빕니다 .

uniform_int 당신이 원하는 것을해야합니다.


나는 merseinne twister로 uniform_int에 대해 약간의 작업을했고, 불행히도 어떤 범위에서는 uniform_int에 의해 반환 된 값이 내가 예상했던 것만 큼 균일하지 않습니다. 예를 들어 uniform_int <> (0, 3)는 1 또는 2보다 0을 더 많이 생성하는 경향이 있습니다.
ScaryAardvark 2010

@ScaryAardvark는 uniform_int그때 의 나쁜 구현처럼 들립니다 . 공정한 출력을 생성하는 것은 매우 쉽습니다. 여기에는 방법을 보여주는 여러 질문이 있습니다.
Mark Ransom

@ 마크 랜섬. 예, 전적으로 동의합니다.
ScaryAardvark

8

속도가 아닌 임의성에 관심이 있다면 안전한 난수 생성 방법을 사용해야합니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 가장 쉬운 방법은 OpenSSL의 난수 생성기를 사용하는 것 입니다.

암호화 알고리즘 (예 : AES )을 사용하여 직접 작성할 수도 있습니다 . 시드와 IV 를 선택한 다음 암호화 기능의 출력을 계속해서 다시 암호화합니다. OpenSSL을 사용하는 것이 더 쉽지만 덜 남성적입니다.


타사 라이브러리를 사용할 수없는 경우 C ++로만 제한됩니다.
anand

그런 다음 남자 다운 경로로 이동하여 AES 또는 다른 암호화 알고리즘을 구현하십시오.
SoapBox

2
RC4는 코드 작성이 간단하고 모든 실용적인 목적에 충분히 무작위입니다 (WEP 제외, RC4의 잘못은 아닙니다). 정말 사소한 코드입니다. 20 줄 정도. Wikipedia 항목에는 의사 코드가 있습니다.
Steve Jessop

4
타사 코드를 사용할 수없는 이유는 무엇입니까? 이것이 숙제 질문이라면, 많은 사람들이이 경우 완전한 해결책을 제공하는 대신 유용한 힌트를 제공하기 때문에 그렇게 말해야합니다. 숙제가 아니라면 "제 3 자 코드가 없습니다"라고 말하는 사람을 쫓아 내십시오. 왜냐하면 그는 바보이기 때문입니다.
DevSolar 2010

OpenSSL rand () 함수 문서에 대한 직접 링크 : openssl.org/docs/crypto/rand.html#
DevSolar 2010

5

RAND_MAX특정 컴파일러 / 환경을 살펴 봐야 합니다. 나는 당신이 이러한 결과를 볼 것이라고 생각합니다rand()임의의 16 비트 숫자를 생성 입니다. (32 비트 숫자라고 가정하고있는 것 같습니다.)

이것이 답이라고 약속 할 수는 없지만의 가치 RAND_MAX와 환경에 대한 자세한 내용을 게시 해주세요 .


3

무엇을 확인 RAND_MAX시스템에 16 비트에 불과하고 범위가 너무 큽니다.

그 외에도 원하는 범위 내에서 임의 정수 생성C rand () 함수 사용 (또는 사용하지 않음)에 대한 참고 사항에 대한이 토론을 참조하십시오 .


Ok RAND_MAX는 32767입니다. 저는 C ++ Windows 플랫폼에 있습니다. 균일 한 분포로 난수를 생성하는 다른 방법이 있습니까?
anand

2

이것은 코드가 아니지만이 논리가 도움이 될 수 있습니다.

static double rnd(void)
{
   return (1.0 / (RAND_MAX + 1.0) * ((double)(rand())) );
}

static void InitBetterRnd(unsigned int seed)
{
    register int i;
    srand( seed );
    for( i = 0; i < POOLSIZE; i++){
        pool[i] = rnd();
    }
}

 // This function returns a number between 0 and 1
 static double rnd0_1(void)
 {
    static int i = POOLSIZE-1;
    double r;

    i = (int)(POOLSIZE*pool[i]);
    r = pool[i];
    pool[i] = rnd();
    return (r);
}

2

숫자가 범위에 걸쳐 균일하게 분포되도록하려면 범위를 필요한 포인트 수를 나타내는 여러 개의 동일한 섹션으로 분할해야합니다. 그런 다음 각 섹션에 대해 최소 / 최대가있는 난수를 얻습니다.

또 다른 참고로, rand()실제로 난수를 생성하는 데 그다지 좋지 않기 때문에 사용하지 말아야 합니다. 어떤 플랫폼에서 실행 중인지 모르겠지만 .NET과 같은 더 나은 함수가있을 수 있습니다 random().


1

[low, high)전체 범위가 RAND_MAX 미만인 한 부동 소수점을 사용하지 않고 범위에 걸쳐 균일 한 분포를 제공해야합니다 .

uint32_t rand_range_low(uint32_t low, uint32_t high)
{
    uint32_t val;
    // only for 0 < range <= RAND_MAX
    assert(low < high);
    assert(high - low <= RAND_MAX);

    uint32_t range = high-low;
    uint32_t scale = RAND_MAX/range;
    do {
        val = rand();
    } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range
    return val/scale + low;
}

RAND_MAX보다 큰 값의 경우 다음과 같은 것을 원합니다.

uint32_t rand_range(uint32_t low, uint32_t high)
{
    assert(high>low);
    uint32_t val;
    uint32_t range = high-low;
    if (range < RAND_MAX)
        return rand_range_low(low, high);
    uint32_t scale = range/RAND_MAX;
    do {
        val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval
    } while (val >= range);
    return val + low;
}

이것은 대략 std :: uniform_int_distribution이하는 일입니다.


0

본질적으로 작은 난수 샘플은 균일하게 분포 할 필요가 없습니다. 결국 그들은 무작위입니다. 난수 생성기가 지속적으로 그룹화되는 것처럼 보이는 숫자를 생성하는 경우 아마도 문제가있을 수 있다는 데 동의합니다.

그러나 무작위성이 반드시 균일하지는 않다는 점을 명심하십시오.

편집 : 명확히하기 위해 "작은 샘플"을 추가했습니다.


"균일 분포"는 잘 정의 된 의미를 가지며 일반적으로 표준 랜덤 생성기가 가깝습니다.
peterchen

예, 맞습니다. 난수 생성기는 시간지남 에 따라 일반적으로 분포가 균일 한 출력을 생성해야합니다 . 내 요점은 적은 수의 인스턴스 (예제에 표시된 6 개)에서 출력이 항상 균일하지는 않다는 것입니다.
Kluge

클루지가 옳다. 작은 표본의 균일 분포는 표본이 확실히 무작위 가 아님을 나타냅니다 .
Bill the Lizard

1
빌, 그런 건 없다는 뜻이에요 작은 샘플은 대부분 무의미하지만 RNG가 균일하고 출력이 균일하다면 왜 균일하지 않은 작은 샘플보다 더 나쁜 것일까 요?
Dan Dyer

2
어느 쪽이든 유의미한 분포는 비 랜덤 성을 나타냅니다. Bill은 단지 6 개의 동일한 간격의 결과도 의심 스럽다는 것을 의미한다고 생각합니다. OP에서 6 개의 값은 32k / 4M 범위 또는 원하는 범위의 1 % 미만입니다. 이것이 거짓 양성일 확률은 너무 작아서 논쟁 할 수 없습니다.
Steve Jessop

0

1과 10 사이의 숫자에 대해 man 3 rand가 제공하는 솔루션 은 다음과 같습니다.

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

귀하의 경우에는 다음과 같습니다.

j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));

물론 이것은 다른 메시지가 지적하는 것처럼 완벽한 임의성 또는 균일 성은 아니지만 대부분의 경우에 충분합니다.


1
이것은 단순히 분포 더 고르게 나타나 도록 재 배열 할뿐 , 실제로는 더 이상 넓은 범위 (OP의 경우)에 대해 더 이상 아닙니다.
Mooing Duck 2013 년

0

@해결책 ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

경고 : 늘이기 및 가능한 정밀도 오류 (RAND_MAX가 충분히 큰 경우에도)로 인해 [min, max]의 모든 숫자가 아닌 균등하게 분산 된 "bins"만 생성 할 수 있다는 점을 잊지 마십시오.


@ 솔루션 : Bigrand

경고 : 이렇게하면 비트가 두 배가되지만 일반적으로 범위의 모든 숫자를 생성 할 수는 없습니다. 즉, BigRand ()가 해당 범위 사이의 모든 숫자를 생성한다는 것이 반드시 사실은 아닙니다.


정보 : rand ()의 범위가 간격 범위를 초과하고 rand ()가 "uniform"이면 접근 방식 (모듈로)은 "괜찮습니다". 최대 첫 번째 최대-최소 숫자에 대한 오류는 1 / (RAND_MAX +1)입니다.

또한 rand ()보다 더 나은 다양한 구현을 제공하는 C ++ 11 의 새로운 임의 패키지 e 로 전환하는 것이 좋습니다 .


0

이것이 내가 생각해 낸 해결책입니다.

#include "<stdlib.h>"

int32_t RandomRange(int32_t min, int32_t max) {
    return (rand() * (max - min + 1) / (RAND_MAX + 1)) + min;
}

이것은 개념적으로 rand() / RAND_MAX0-1 사이의 부동 소수점 범위를 얻은 다음이를 버킷으로 반올림하는 데 사용하는 솔루션과 유사한 버킷 솔루션 입니다. 그러나 순전히 정수 수학을 사용하고 정수 분할 바닥을 활용하여 값을 가장 가까운 버킷으로 반올림합니다.

몇 가지 가정을합니다. 첫째, 그것은 RAND_MAX * (max - min + 1)항상 int32_t. 경우 RAND_MAX구현이 훨씬 더 큰 RAND_MAX가있는 경우 32767 및 32 비트 INT 계산이 사용되면, 최대 당신이 가질 수있는 범위는 것은 32767, 당신은 더 큰 정수 (같은 사용하여이를 극복 할 수 int64_t계산을위한 참조). 둘째, int64_t사용되지만 RAND_MAX여전히 32767이면 RAND_MAX가능한 출력 번호에 "구멍"이 생기기 시작합니다. 이것은 확장에서 파생 된 모든 솔루션의 가장 큰 문제 일 것입니다 rand().

그럼에도 불구하고 엄청난 수의 반복에 대한 테스트는이 방법이 작은 범위에 대해 매우 균일하다는 것을 보여줍니다. 그러나 수학적으로 이것은 약간의 편향이 있고 범위가에 가까워지면 문제가 발생할 수 있습니다 RAND_MAX. 직접 테스트하고 요구 사항을 충족하는지 결정하십시오.


-1

물론 다음 코드는 난수를 제공하지 않고 의사 난수를 제공합니다. 다음 코드를 사용하십시오.

#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )

예를 들면 :

int myRand = QUICK_RAND(10, 20);

당신은 전화해야합니다

srand(time(0));  // Initialize random number generator.

그렇지 않으면 숫자가 거의 무작위가 아닙니다.


1
문제는 균일 한 분포를 요구하는 것입니다. 이 제안 된 솔루션은 균일 한 분포를 생성하지 않습니다. 표준 C ++ 라이브러리에는 의사 난수 생성 기능이 있습니다. 사람들은 요청이있는 경우, 균일 한 분포를 제공한다.
IInspectable

-3

방금 인터넷에서 찾았습니다. 이것은 작동합니다.

DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));

PRNG에 대한 수많은 알고리즘이 필요합니다. 또한 답변을 게시하는 대신 주요 질문을 편집하면 더 쉬울 것입니다.
peterchen

이것은 나를 위해 가장 잘 작동합니다 ...이 공식을 사용하여 더 나은 분산 난수를 얻을 수 있습니다.
anand

4
범위가 RAND_MAX를 초과하면 결과가 균일 하지 않을 수 있습니다. 즉, 함수를 몇 번 호출해도 표현되지 않는 범위의 값이 있습니다.
dmckee --- 전 중재자 새끼 고양이

4
또한 max와 min이 모두 unsigned int이고 min이 0이고 max가 MAX_UINT이면 ((max)-(min) +1)은 0이되고 결과는 항상 0이됩니다. 이런 종류의 수학을하는 오버플로를 조심하세요! dmckee에서 언급했듯이 이는 대상 범위에 걸쳐 분포를 확장하지만 RAND_MAX 고유 값 이상을 보장하지는 않습니다.
제섭
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.