전체 범위에서 균일하게 난수 생성
지정된 간격 [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 플랫폼에 있습니다. 균등 분포로 난수를 생성하는 다른 방법이 있습니까?
왜 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);
알고리즘은 선형 복잡도로 요소를 무작위로 재정렬합니다.
부스트. 랜덤
C ++ 11 + 컴파일러에 액세스 할 수없는 경우 다른 대안은 Boost.Random 을 사용하는 것 입니다. 인터페이스는 C ++ 11 인터페이스와 매우 유사합니다.
[편집] 경고 : 음주 사용하지 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 이 훌륭하고 구현하기 간단 하다는 것을 발견 했습니다.
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 (문서) 은 <random>
인터페이스의 대부분을 공유 하는 C ++ 11에 영감을 준 라이브러리입니다 . 이론적으로는 외부 종속성이기도하지만 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
mt19937
athread_local
: the generator is quite plump (> 2 KB) and is better not allocated on the stack - seed
mt19937
with more than one integer: the Mersenne Twister has a big state and can take benefit of more entropy during initialization
Some not-so-good choices
The C++11 library
While being the most idiomatic solution, the <random>
library does not offer much in exchange for the complexity of its interface even for the basic needs. The flaw is in std::random_device
: the Standard does not mandate any minimal quality for its output (as long as entropy()
returns 0
) and, as of 2015, MinGW (not the most used compiler, but hardly an esoterical choice) will always print 4
on the minimal sample.
Minimal sample: a die roll
#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';
}
If the implementation is not rotten, this solution should be equivalent to the Boost one, and the same suggestions apply.
Godot's solution
Minimal sample: a die roll
#include <iostream>
#include <random>
int main() {
std::cout << std::randint(1,6);
}
This is a simple, effective and neat solution. Only defect, it will take a while to compile – about two years, providing C++17 is released on time and the experimental randint
function is approved into the new Standard. Maybe by that time also the guarantees on the seeding quality will improve.
The worse-is-better solution
Minimal sample: a die roll
#include <cstdlib>
#include <ctime>
#include <iostream>
int main() {
std::srand(std::time(nullptr));
std::cout << (std::rand() % 6 + 1);
}
The old C solution is considered harmful, and for good reasons (see the other answers here or this detailed analysis). Still, it has its advantages: is is simple, portable, fast and honest, in the sense it is known that the random numbers one gets are hardly decent, and therefore one is not tempted to use them for serious purposes.
The accounting troll solution
Minimal sample: a die roll
#include <iostream>
int main() {
std::cout << 9; // http://dilbert.com/strip/2001-10-25
}
While 9 is a somewhat unusual outcome for a regular die roll, one has to admire the excellent combination of good qualities in this solution, which manages to be the fastest, simplest, most cache-friendly and most portable one. By substituting 9 with 4 one gets a perfect generator for any kind of Dungeons and Dragons die, while still avoiding the symbol-laden values 1, 2 and 3. The only small flaw is that, because of the bad temper of Dilbert's accounting trolls, this program actually engenders undefined behavior.
If RAND_MAX is 32767, you can double the number of bits easily.
int BigRand()
{
assert(INT_MAX/(RAND_MAX+1) > RAND_MAX);
return rand() * (RAND_MAX+1) + rand();
}
If you are able to, use Boost. I have had good luck with their random library.
uniform_int
should do what you want.
If you are concerned about randomness and not about speed, you should use a secure random number generation method. There are several ways to do this... The easiest one being to use OpenSSL's Random Number Generator.
You can also write your own using an encryption algorithm (like AES). By picking a seed and an IV and then continuously re-encrypting the output of the encryption function. Using OpenSSL is easier, but less manly.
You should look at RAND_MAX for your particular compiler/environment. I think you would see these results if rand() is producing a random 16-bit number. (you seem to be assuming it will be a 32-bit number).
I can't promise this is the answer, but please post your value of RAND_MAX, and a little more detail on your environment.
Check what RAND_MAX is on your system -- I'm guessing it is only 16 bits, and your range is too big for it.
Beyond that see this discussion on: Generating Random Integers within a Desired Range and the notes on using (or not) the C rand() function.
If you want numbers to be uniformly distributed over the range, you should break your range up into a number of equal sections that represent the number of points you need. Then get a random number with a min/max for each section.
As another note, you should probably not use rand() as it's not very good at actually generating random numbers. I don't know what platform you're running on, but there is probably a better function you can call like random().
This is not the code, but this logic may help you.
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();
}
}
static double rnd0_1(void)
{ // This function returns a number between 0 and 1
static int i=POOLSIZE-1;
double r;
i = (int)(POOLSIZE*pool[i]);
r=pool[i];
pool[i]=rnd();
return (r);
}
This should provide a uniform distribution over the range [low, high)
without using floats, as long as the overall range is less than 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;
}
and for values greater than RAND_MAX you want something like
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;
}
This is roughly how std::uniform_int_distribution does things.
By their nature, a small sample of random numbers doesn't have to be uniformly distributed. They're random, after all. I agree that if a random number generator is generating numbers that consistently appear to be grouped, then there is probably something wrong with it.
But keep in mind that randomness isn't necessarily uniform.
Edit: I added "small sample" to clarify.
The solution given by man 3 rand for a number between 1 and 10 inclusive is:
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
In your case, it would be:
j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));
Of course, this is not perfect randomness or uniformity as some other messages are pointing out, but this is enough for most cases.
@Solution ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min
Warning: Don't forget due to stretching and possible precision errors (even if RAND_MAX were large enough), you'll only be able to generate evenly distributed "bins" and not all numbers in [min,max].
@Solution: Bigrand
Warning: Note that this doubles the bits, but still won't be able to generate all numbers in your range in general, i.e., it is not necessarily true that BigRand() will generate all numbers between in its range.
Info: Your approach (modulo) is "fine" as long as the range of rand() exceeds your interval range and rand() is "uniform". The error for at most the first max - min numbers is 1/(RAND_MAX +1).
Also, I suggest to switch to the new random packagee in C++11 too, which offers better and more varieties of implementations than rand().
Of course, the following code won't give you random numbers but pseudo random number. Use the following code
#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )
For example:
int myRand = QUICK_RAND(10, 20);
You must call
srand(time(0)); // Initialize random number generator.
otherwise the numbers won't be near random.
I just found this on the Internet. This should work:
DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));
참고URL : https://stackoverflow.com/questions/288739/generate-random-numbers-uniformly-over-an-entire-range
'Development Tip' 카테고리의 다른 글
파일 또는 어셈블리 System.Net.Http, 버전 = 4.0.0.0을 ASP.NET (MVC 4) 웹 API OData 프리 릴리즈와 함께로드 할 수 없습니다. (0) | 2020.09.25 |
---|---|
Postgres의 테이블에 대한 쿼리 부여 (0) | 2020.09.25 |
NumPy를 사용하여 이동 평균을 계산하는 방법은 무엇입니까? (0) | 2020.09.25 |
16 진수 RGB 문자열에서 System.Drawing.Color를 만드는 방법은 무엇입니까? (0) | 2020.09.25 |
Xcode 4 오류 : 실행 파일 시작 오류 (0) | 2020.09.25 |