2011-02-16 3 views
2

C++의 난수 생성에는 약간의 제한이 있다는 것을 알고 있습니다 (비 균일 할 수 있음). 1에서 14620까지의 숫자를 생성하려면 어떻게해야합니까?난수 생성기, C++

감사합니다.

+0

지금 심지어 C++에서 임의의 숫자를 사용하는 방법을 찾아 볼나요 :

이 예는 트릭을 할해야합니까? 또한 C++에서 임의의 숫자로 작성된 더 나은 솔루션이 필요하거나 단순히 rand 사용 방법에 대해 설명하는 경우를 언급하지 않았습니다. – thecoshman

+0

C++에 고유 한 "난수 생성 제한 사항"이 무엇을 의미하는지 명확히 할 수 있습니까? 다소 균일 한 시퀀스는 더 좋거나 적은 발전기에서 발생합니다. – Francesco

+0

rand()가 (균일하지 않을 수 있다면)별로 유용하지 않을 것입니다. –

답변

17

일반적인 방법은 모듈로 std::rand()을 사용하는 것이다 @tenfour 그의 대답 언급로

#include<cstdlib> 
#include<ctime> 

// ... 
std::srand(std::time(0)); // needed once per program run 
int r = std::rand() % 14620 + 1; 

그러나, 모듈러스 연산자 값 std::rand() 복귀의 균일 성을 방해 할 수있다. 이것은 모듈러스가 버려지는 값을 유효한 값으로 변환하기 때문이며,이 변환은 일정하지 않을 수 있습니다. 예를 들어, [0, 10]의 n의 경우 값 n % 9은 9를 0으로 변환하므로 true 0 또는 9로 0을 얻을 수 있습니다. 다른 값은 각각 한 번만 얻을 수 있습니다.

대체 접근법은 std::rand()의 난수를 [0, 1] 범위의 부동 소수점 값으로 변환 한 다음 원하는 범위 내로 값을 변환하고 이동하는 것입니다.

int r = static_cast<double>(std::rand())/RAND_MAX * 14620 + 1; 
4

rand을 사용하십시오.

(rand() % 100) is in the range 0 to 99 
(rand() % 100 + 1) is in the range 1 to 100 
(rand() % 30 + 1985) is in the range 1985 to 2014 

(rand() % 14620 + 1) is in the range 1 to 14620 

EDIT은 : ​​

링크에서 언급했듯이

, 랜더 마이저를 사용 전에 srand 시드를 사용한다. 사용할 공통적 인 가치는 time으로 전화 한 결과입니다. 다른 사람이 대답대로

+3

중요한 추가 정보는 빠졌습니다. *이 모듈러스 연산은 스팬에 진정으로 균일하게 분포 된 난수를 생성하지 않습니다. * – meagar

+0

시드를 사용하지 않고 오른쪽. 링크는 페이지 하단에 시드를 언급합니다. 이것을 포함하도록 업데이트하겠습니다. – James

+0

@James, @meagar, 어떻게하면 균일하게 분산 된 난수를 생성 할 수 있을까요? 알고리즘의 한 루프 내에서 30,000 개를 생성해야합니다. – notrockstar

11

srand()/rand()는 당신이 필요로하는 기능이다 부스트 라이브러리를 사용하여 튜토리얼입니다.

%의 문제점은 결과가 분명히 균일하지 않다는 것입니다. 예를 들어, rand()이 0-3의 범위를 반환한다고 상상해보십시오.

0 - 2000 times 
1 - 1000 times 
2 - 1000 times 

아야 : 당신이 (rand() % 3)에 대해 동일한 샘플링을 할 경우

0 - 1000 times 
1 - 1000 times 
2 - 1000 times 
3 - 1000 times 

지금, 당신은 결과가 같을 것이라고주의 사항 : 여기에 가상 그것을 4000 번 호출의 결과는! 더 균일 한 해결책은 이것이다 : 정치 못한 코드에 대한

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

미안하지만, 아이디어는 부동 소수점 연산을 사용하여 원하는 범위를 적절하게 축소하고, 정수로 변환하는 것입니다. 당신이 C + +0 환경, 부스트 LIB의 가까운 유도체를 가지고있는 경우에

+0

: +1 좋은 지적입니다. – wilhelmtell

+0

'(((double) std :: rand())/RAND_MAX)'-이 부분에 대해 설명해 주시겠습니까? 난수를 생성 한 다음 RAND_MAX로 스케일을 조정합니까? – notrockstar

+0

을'RAND_MAX'로 나눔으로써 0.0에서 1.0 사이의 균일 한 난수를 생성합니다. 따라서 원하는 범위로 쉽게 확장 할 수 있습니다. 너의 경우, 1-14620. – tenfour

18

이제 표준 :

#include <random> 
#include <iostream> 

int main() 
{ 
    std::uniform_int_distribution<> d(1, 14620); 
    std::mt19937 gen; 
    std::cout << d(gen) << '\n'; 
} 

이 빠르고, 쉽고 높은 품질 될 것입니다.

당신은 지정하지만, 대신 부동 소수점 원한다면 그냥 하위하지 않았다 :

std::uniform_real_distribution<> d(1, 14620); 

그리고 당신은 비 균일 한 분포를 필요한 경우, 당신은 당신의 자신의 작품이 많다는 상수 또는 piece-을 구축 할 수 있습니다 현명한 선형 분포가 매우 쉽습니다.

+0

균일 한 int 분포와 uniform real 분포 사이에는 중요한 차이가 있음에 유의하십시오. 균일 한 int 분포는 '닫힌 범위'[1,14620]의 숫자를 반환하고 균일 한 실제 분포는 '반 개방 범위'의 숫자를 반환합니다 [1,14620]. – Blastfurnace

+1

C++ 0x-esque 시드도 사용할 수 있습니다.'std :: random_device r; std :: mt19937 gen (r());' – Cubbi

+0

그리고 C++ 0x가 없다면 boost :: random은 아마도 당신이 정말로 빠르고 더러운 것을 필요로하지 않는다면 아마 표준이 될 것입니다 ... – Chinasaur

1

이미 말한 것처럼 rand()을 사용할 수 있습니다. 예 :

int n = rand() % 14620 + 1;

는 일을하지만, 비 균일하다. 즉, 약간의 값 (낮은 값)이 약간 더 자주 발생 함을 의미합니다. 이는 rand()이 0에서 RAND_MAX 범위의 값을 산출하고 RAND_MAX이 일반적으로 14620으로 나눌 수 없기 때문입니다. RAND_MAX == 15000 일 경우 rand() == 0rand() == 14620이 모두 n==1이지만 rand()==999 만 출력하면 n==1000이되므로 숫자 1은 숫자 1000의 두 배가됩니다.

그러나 14620이 RAND_MAX보다 훨씬 작 으면이 효과는 무시할 수 있습니다. 내 컴퓨터에서 RAND_MAX은 2147483647과 같습니다. rand()은 2147483647 % 14620 = 10327 및 2147483647/14620 = 146886이므로 균등 한 샘플을 0에서 RAND_MAX로 산출하면 n은 평균 146887 번, 1에서 10328 사이이며 10329와 2147483647 샘플을 그릴 경우 14620이 평균 146886 번 발생합니다. 나 한테 큰 차이가 없다.

그러나 RAND_MAX == 15000 인 경우 위의 설명과 같이 변경됩니다. 이 경우 일부 이전 게시물

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

가 '더 균일'하기 위해 사용하는 제안했다. rand()은 여전히 ​​유일한 값 RAND_MAX의 고유 값을 반환하므로 더 자주 발생하는 숫자 만 변경됩니다. 정말 균일하게 만들려면 정수형 rand()이 14620 * int (RAND_MAX/14620)와 RAND_MAX 사이의 범위에 있고 rand()을 다시 호출해야합니다. RAND_MAX == 15000의 예제에서는 rand()의 값을 14620과 15000 사이에서 거부하고 다시 그립니다. 대부분의 응용 프로그램에서는 이것이 필요하지 않습니다. 난 rand()의 임의성에 대해 더 걱정할 것입니다.

0

계수 운영자가 가장 중요하다,이 계수에 제한을 적용 할 수 있습니다,이 체크 아웃 :

// random numbers generation in C++ using builtin functions 
#include <iostream> 

using namespace std; 

#include <iomanip> 

using std::setw; 

#include <cstdlib> // contains function prototype for rand 

int main() 
{ 
// loop 20 times 
for (int counter = 1; counter <= 20; counter++) { 

    // pick random number from 1 to 6 and output it 
    cout << setw(10) << (1 + rand() % 6); 

    // if counter divisible by 5, begin new line of output 
    if (counter % 5 == 0) 
     cout << endl; 

} 

return 0; // indicates successful termination 

} // end main 
1

랜드를() 함수는 정말 최고의 랜덤 생성기 아니라, 더 좋은 방법이 될 것이다 CryptGenRandom()을 사용하여.

#include <Windows.h> 

// Random-Generator 
HCRYPTPROV hProv; 
INT Random() { 
    if (hProv == NULL) { 
     if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) 
      ExitProcess(EXIT_FAILURE); 
    } 

    int out; 
    CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out)); 
    return out & 0x7fffffff; 
} 

int main() { 
    int ri = Random() % 14620 + 1; 
}