C ++ rand ()가 같은 크기의 숫자 만 생성하는 이유는 무엇입니까?


146

C / C ++로 작성된 작은 응용 프로그램에서 rand함수와 시드에 문제가 있습니다 .

다른 순서, 즉 다른 로그 값 (베이스 2)의 난수 시퀀스를 생성하고 싶습니다. 그러나 생성 된 모든 숫자는 동일한 순서이며 2 ^ 25와 2 ^ 30 사이에서 변동합니다.

rand()지금은 비교적 큰 숫자 인 유닉스 타임이 뿌려 졌기 때문 입니까? 내가 무엇을 잊고 있습니까? 나는 rand()시작 부분에 한 번만 시드 합니다 main().


7
그렇다면 C 또는 C ++입니까? C / C ++에 의해 실제로 C ++을 사용할 수 있고 C에 대한 언급이 무작위 인 경우이 en.cppreference.com/w/cpp/numeric/random/binomial_distribution 이 도움 이 수 있습니다.
R. Martinho Fernandes 2013 년

9
불행히도 당신은 잘못된 말에 베팅했습니다. 씨앗은 당신의 문제가되어서는 안됩니다. 문제가 잘못된 예상 배포판입니다. 편견이없는 프로그래머는 rand()균일하게 분포 된 숫자 (Google 순위가 높은 문서에 명시 적으로 나와 있음)를 반환 할 것으로 예상하므로이 질문이 향후 독자에게 유용하지 않다고 생각합니다. 그래서 투표를 거부하지만 SO를 사용하지 못하게하십시오.
황제 오리온 ii

12
@ doug65536 "... 반복되는 숫자가 없습니다"-무작위가 아닙니다! 가능한 모든 숫자가 반환 될 때까지 rand () 주사위가 같은 숫자를 두 번 반환하지 않으면 쓰레기 테이블에서 퇴직 자금을 지원할 수 있습니다.
Chris Gregg

6
@GalacticCowboy 반복되는 개별 숫자로 주기성을 착각하지 마십시오. Wikipedia 기사에서 "반복 된 결과는 내부 상태가 출력보다 클 수 있기 때문에 기간의 끝에 도달했음을 의미하지 않습니다." PRNG가 값을 생성 한 다음 모든 값이 반환 될 때까지 해당 값을 다시 생성하지 않는 것이 매우 나쁩니다.
Chris Gregg

12
Doug65536, 아무도 싸움을 선택하지 않습니다. 그들은 당신이 틀렸다는 것을 정확하게 진술하고 있습니다. PRNG는 1과 10 사이의 RAND를 원한다면 다음과 같이 만족스럽게 만들 수 있습니다. PRNG가 iPhone의 셔플 기능과 혼동되고 있다고 생각합니다.
키프로스에서 휴식

답변:


479

1과 2 사이의 숫자의 3 %가있다 (30) NOT 2 사이 (25) , 2 (30) . 그래서, 이것은 꽤 정상적인 소리입니다 :)

이 때문에, 25 / 2 30 = 2 -5 = 1/32 = 0.03125 = 3.125 %


36
예, 좋은 지적입니다! 2 ^ 25와 2 ^ 30 사이의 숫자는 1과 2 ^ 25 사이의 숫자보다 31 배 더 많습니다. 그런 다음 프로그램을 다시 생각해야합니다. 질문에 답변했습니다.
Tallaron Mathias 2016 년

1
@TallaronMathias 비트 시프 팅을 통해 숫자를 자르는 것을 고려하십시오 >>. 그러면 작은 숫자가 제공됩니다. (또는 모듈러스를 사용하여 %.)
Sean Allred

13
나는 이것이 대부분의 프로그래머에게 명백 할 것으로 예상한다 : 2 ^ 25보다 작은 부호없는 정수는 첫 7 비트가 같아야한다 0-그리고 모든 비트가 무작위라면 ...
BlueRaja-Danny Pflughoeft

118
@ BlueRaja-DannyPflughoeft-확률이 명백한 경우 카지노는 비즈니스에서 벗어날 수 있습니다.
Brett Hale

26
@BrettHale-프로그래머가 카지노의 목표 인구 통계라고 생각하지 않습니다.
EkoostikMartin 2016 년

272

연한 녹색은 0과 2 25 사이의 영역입니다 . 짙은 녹색은 2 25 와 2 30 사이의 영역 입니다. 진드기는 2의 거듭 제곱입니다.

분포


42

더 정확해야합니다 : 다른 기본 2 로그 값을 원하지만 어떤 분포 를 원하십니까? 표준 rand () 함수는 균일 분포를 생성하므로 원하는 분포와 연관된 Quantile 함수를 사용하여이 출력을 변환해야합니다 .

배포판을 알려 주면 필요한 quantile기능을 알려줄 수 있습니다 .


13
+1, 분배 는 중요한 용어입니다. 분포에 대해 알려진 것이 없으면 난수에 대해 말하는 것이 실제로 의미가 없습니다. 유니폼은 중요한 경우이지만 특별한 경우입니다. C ++ 11 표준 라이브러리에서 다양한 배포판을 지적하기에 좋은 장소 일 수 있습니다.
leftaroundabout

18

다른 크기의 순서를 원한다면 단순히 시도해보십시오 pow(2, rand()). 아니면 Harold가 제안한 것처럼 rand ()로 직접 주문을 선택합니까?


3
좋은 생각이지만 ^ 대신 pow를 사용하여 답을 고쳐야합니다 (C 언어에서는 권력이 아닌 논리적 xor 연산자입니다).
kriss 2016 년

6
이후 rand()까지 갈 수있는 RAND_MAX결과가 ... 오버 플로우하지 않도록, 당신은 정말 당신의 임의의 숫자를 확장 할 필요가
플로리스

@Floris : 그러나 매우 넓은 범위에서 소수의 셀 수있는 범위를 확장하면 많은 구멍이 생길 것입니다. 아마도 OP가 기대하지 않는 것입니다.
André Caron 2016 년

13

@ C4stor가 좋은 지적을했습니다. 그러나 더 일반적인 경우와 인간 (베이스 10)에 대해 이해하기 쉽도록 1 ~ 10 ^ n 범위에서 숫자의 ~ 90 %는 10 ^ (n-1) ~ 10 ^ n입니다. 숫자의 ~ 99 %가 10 ^ (n-2)에서 10 ^ n으로 이동합니다. 원하는만큼 소수점을 계속 추가하십시오.

재미있는 수학, n을 위해 이것을 계속하면,이 방법으로 1에서 10 ^ n, 99.9999 ... % = 100 % 의 숫자가 10 ^ 0에서 10 ^ n 사이임을 알 수 있습니다.

이제 코드에 대해 0에서 10 ^ n 사이의 임의의 크기의 난수를 원한다면 다음을 수행 할 수 있습니다.

  1. 0에서 n까지 작은 난수 생성

  2. n의 범위를 알고 있다면 k> max {n} 인 10 ^ k의 큰 난수를 생성하십시오.

  3. 이 큰 난수의 n 자리를 얻으려면 더 긴 난수를 자릅니다.


46
당신은 완전히 정확하지만, 이해하기 쉬운 대답을 위해 OP는 1에서 100 사이의 난수의 90 %가 두 자리 숫자 인 이유를 스스로에게 묻어 야합니다.
Monica에 대해 문의하기

13

기본 (정확한) 대답은 이미 위에서 주어졌고 수락되었습니다 .0과 9 사이의 10 숫자, 10과 99 사이의 90 숫자, 100과 999 사이의 900 등이 있습니다.

대략 로그 분포를 갖는 분포를 계산하는 효율적인 방법을 위해 임의의 숫자를 임의의 숫자로 오른쪽으로 이동하려고합니다.

s = rand() & 31; // a random number between 0 and 31 inclusive, assuming RAND_MAX = 2^32-1
r = rand() >> s; // right shift

완벽하지는 않지만 컴퓨팅보다 훨씬 빠릅니다 pow(2, rand()*scalefactor). 분포는 요소 2 (128에서 255에 대해 균일하고 256에서 1023에 대한 밀도의 절반 등) 내의 숫자에 대해 분포가 균일하다는 의미에서 "거칠게"나타납니다.

다음은 숫자 0에서 31까지의 빈도 (1M 샘플)의 히스토그램입니다.

여기에 이미지 설명을 입력하십시오


nitpick : 이것은 예상보다 매우 적은 숫자를 권장합니다. 0을 얻을 확률은 10보다 상당히 높습니다.
Mooing Duck

글쎄-이것의 요점은 작은 숫자를 장려하는 것이므로 그것이 효과가있어서 기쁩니다! 나는 몬테카를로 시뮬레이션을 실행했는데, 이것은 로그 분포와 달리 숫자가 두 배로 나올 확률이 2 배나 줄었습니다. 사진으로 답변을 업데이트했습니다.
Floris

아니요, rand()>>(rand()&31);를 사용하면 1/32 번째 숫자는 32 비트를, 1/32 번째 숫자는 31 비트를, 1/32 번째 숫자는 30 비트를 직관적으로 기대합니다. 아니 거의 절반 측정 내 정신 수학 동의하지 이후 0이되어야하는 동안 단 1 이상에 대해,지고있어 결과가 / 숫자 64는 내가 그림을 내 자신의 측정을해야 할 것이다, 32 비트 초래 이 아웃.
Mooing Duck

2
귀하의 코드가 잘못되었다는 의미는 아닙니다. 아마 내가 할 것입니다. 그냥 결과가되지 않도록 경고 가치가 매우 하나가 예상대로 분산을.
Mooing Duck

1
문제는 0을 1 비트 숫자로 생각할 때 발생한다고 생각합니다. 정수와 로그를 혼합 할 때 수수께끼입니다. 그것은 좋은 운동이었다. 그리고 당신은 나에게 생각할 무엇인가를 줬다. "알고리즘의 한계를 테스트하십시오"-결코 오래되지 않습니다.
Floris

5

0과 2 ^ 29와 2 ^ 29와 2 ^ 30 사이의 숫자는 정확히 같습니다.

문제를 보는 또 다른 방법 : 생성 한 난수의 이진 표현, 가장 높은 비트가 1 일 확률은 1/2과 같으므로 절반의 경우 29를 얻습니다. 원하는 것은 2 ^ 25 이하의 숫자를 보는 것이지만 5 개의 최상위 비트는 모두 0이며 이는 1/32의 낮은 확률로 발생합니다. 오랫동안 실행하더라도 15 미만의 순서는 전혀 볼 수 없습니다 (확률은 6 6 번 연속으로 굴리는 것과 같습니다).

자, 씨앗에 대한 당신의 질문의 일부. 시드는 숫자가 생성되는 범위를 판별 할 수 없으며 첫 번째 초기 요소 만 결정합니다. rand ()를 범위에서 가능한 모든 숫자의 시퀀스 (사전 결정된 순열)로 생각하십시오. 시드는 시퀀스에서 숫자 그리기 시작 위치를 결정합니다. 그렇기 때문에 (의사) 임의성을 원한다면 현재 시간을 사용하여 시퀀스를 초기화하십시오.


2

pow(2,rand()) 그것을 사용 하여 원하는 크기의 순서대로 답변을 줄 것입니다!


2

온라인 서비스에서 난수를 사용하려면 wget을 사용할 수 있습니다. 난수 생성에 random.org와 같은 서비스를 사용할 수도 있습니다 .wget을 사용하여 잡을 수 있습니다. 다운로드 한 파일

wget -q https://www.random.org/integers/?num=100&min=1&max=100&col=5&base=10&format=html&rnd=new -O new.txt

http://programmingconsole.blogspot.in/2013/11/a-better-and-different-way-to-generate.html


SO에 오신 것을 환영합니다. 답변으로 링크를 게시하지 마십시오. 링크를 통해 세부 정보를 읽을 수 있도록 답변의 세부 스케치를 제공 할 수 있습니다.
Shai
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.