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.