C ++에서 임의의 부동 소수점을 어떻게 생성합니까?
정수 랜드를 가져 와서 무언가로 나눌 수 있다고 생각했는데 충분합니까?
답변
rand()
C ++에서 의사 난수를 생성하는 데 사용할 수 있습니다. RAND_MAX
약간의 수학과 함께 사용 하면 원하는 임의의 간격으로 난수를 생성 할 수 있습니다. 학습 목적과 장난감 프로그램에 충분합니다. 정규 분포를 사용하여 실제로 임의의 숫자가 필요한 경우 더 고급 방법을 사용해야합니다.
0.0부터 1.0까지의 숫자가 생성됩니다.
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
이것은 어떤 임의 0.0의 숫자를 생성 할 것이다 float
, X
:
float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));
이것은 어떤 임의의 숫자가 생성됩니다 LO
어떤 임의의로를 HI
:
float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
점을 유의 rand()
당신이 진정으로 임의의 숫자를 필요로하는 경우 함수가 종종 충분하지 않을 것입니다.
전화하기 전에 먼저을 호출 rand()
하여 난수 생성기를 “시드”해야합니다 srand()
. 전화를 걸 때마다 한 번이 아니라 프로그램 실행 중에 한 번 수행해야합니다 rand()
. 이것은 종종 다음과 같이 수행됩니다 :
srand (static_cast <unsigned> (time(0)));
전화를 걸 rand
거나 srand
해야합니다 #include <cstdlib>
.
전화 time
를하려면 다음을 수행해야합니다 #include <ctime>
.
답변
C ++ 11은로 많은 새로운 옵션을 제공 random
합니다. 이 주제에 대한 표준 논문 은 C ++ 11의 난수 생성 N3551입니다.
사용 rand()
이 왜 문제가 될 수 있는지 알아 보려면 GoingNative 2013 행사 에서 제공된 Stephan T. Lavavej 의 rand () 고려 된 유해 프레젠테이션 자료를 참조하십시오 . 슬라이드는 주석에 있지만 여기에 직접 링크가 있습니다.
레거시 코드는 여전히 지원이 필요할 수 있으므로 boost
사용뿐만 아니라 다루고 rand
있습니다.
아래 예제는 cppreference 사이트에서 추출한 std :: mersenne_twister_engine 엔진 및 std :: uniform_real_distribution 을 사용하여 [0,10)
간격 에 따라 숫자를 생성 하고 다른 엔진 및 분배는 주석 처리됩니다 ( 실제 참조 ).
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
std::random_device rd;
//
// Engines
//
std::mt19937 e2(rd());
//std::knuth_b e2(rd());
//std::default_random_engine e2(rd()) ;
//
// Distribtuions
//
std::uniform_real_distribution<> dist(0, 10);
//std::normal_distribution<> dist(2, 2);
//std::student_t_distribution<> dist(5);
//std::poisson_distribution<> dist(2);
//std::extreme_value_distribution<> dist(0,2);
std::map<int, int> hist;
for (int n = 0; n < 10000; ++n) {
++hist[std::floor(dist(e2))];
}
for (auto p : hist) {
std::cout << std::fixed << std::setprecision(1) << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
}
출력은 다음과 유사합니다.
0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****
우리가 가기로 결정하면 출력 그래서, 어떤 당신이 선택하는 분포에 따라 달라집니다 표준 : normal_distribution 의 값이 2
모두 평균 과 STDDEV 예를 들어, dist(2, 2)
대신 출력이 유사하다 ( 이 살고 참조 )
-6
-5
-4
-3
-2 **
-1 ****
0 *******
1 *********
2 *********
3 *******
4 ****
5 **
6
7
8
9
다음은 제시된 일부 코드의 수정 된 버전입니다 N3551
( 실제 참조 ).
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
std::default_random_engine & global_urng( )
{
static std::default_random_engine u{};
return u ;
}
void randomize( )
{
static std::random_device rd{};
global_urng().seed( rd() );
}
int main( )
{
// Manufacture a deck of cards:
using card = int;
std::array<card,52> deck{};
std::iota(deck.begin(), deck.end(), 0);
randomize( ) ;
std::shuffle(deck.begin(), deck.end(), global_urng());
// Display each card in the shuffled deck:
auto suit = []( card c ) { return "SHDC"[c / 13]; };
auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };
for( card c : deck )
std::cout << ' ' << rank(c) << suit(c);
std::cout << std::endl;
}
결과는 다음과 유사합니다.
5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S
후원
물론 Boost.Random 은 항상 옵션입니다. 여기서 boost :: random :: uniform_real_distribution을 사용하고 있습니다 .
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>
int main()
{
boost::random::mt19937 gen;
boost::random::uniform_real_distribution<> dist(0, 10);
std::map<int, int> hist;
for (int n = 0; n < 10000; ++n) {
++hist[std::floor(dist(gen))];
}
for (auto p : hist) {
std::cout << std::fixed << std::setprecision(1) << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
}
랜드()
사용해야하는 경우 부동 소수점 난수를 생성하는 방법 에 대한 지침 rand()
은 C FAQ 를 참조하십시오 . 기본적으로 간격을 생성하기 위해 이와 유사한 예제를 제공합니다 [0,1)
.
#include <stdlib.h>
double randZeroToOne()
{
return rand() / (RAND_MAX + 1.);
}
다음 범위에서 임의의 숫자를 생성합니다 [M,N)
.
double randMToN(double M, double N)
{
return M + (rand() / ( RAND_MAX / (N-M) ) ) ;
}
답변
Boost.Random을 살펴보십시오 . 다음과 같이 할 수 있습니다.
float gen_random_float(float min, float max)
{
boost::mt19937 rng;
boost::uniform_real<float> u(min, max);
boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
return gen();
}
매번 새로운 객체를 생성하는 대신 동일한 mt19937 객체를 전달하는 것이 좋습니다.하지만 아이디어를 얻길 바랍니다.
답변
현대에서는 함께 제공 c++
되는 <random>
헤더를 사용할 수 있습니다 c++11
.
무작위를 얻으려면 float
사용할 수 있습니다 std::uniform_real_distribution<>
.
함수를 사용하여 숫자를 생성 할 수 있으며 숫자가 항상 동일하지 않게 하려면 엔진과 분포를로 설정하십시오 static
.
예:
float get_random()
{
static std::default_random_engine e;
static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
return dis(e);
}
float
의 컨테이너를 다음과 같은 컨테이너에 배치하는 것이 이상적입니다 std::vector
.
int main()
{
std::vector<float> nums;
for (int i{}; i != 5; ++i) // Generate 5 random floats
nums.emplace_back(get_random());
for (const auto& i : nums) std::cout << i << " ";
}
출력 예 :
0.0518757 0.969106 0.0985112 0.0895674 0.895542
답변
두 가지 float
값으로 코드를 호출하면 코드가 모든 범위에서 작동합니다.
float rand_FloatRange(float a, float b)
{
return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
답변
C가 아닌 C ++을 사용하는 경우 기술 보고서 1 (TR1)과 C ++ 0x 초안에서 헤더 파일에 난수 생성기를위한 기능을 추가했다는 점을 기억하십시오. 부스트와 동일하다고 생각합니다. 랜덤 라이브러리이며 C 라이브러리 함수보다 훨씬 유연하고 “현대”랜드.
이 구문은 발전기 ( 메르 센 트위스터 mt19937 와 같은 )를 선택한 다음 분포 (일반, 베르누이, 이항 등) 를 선택할 수있는 기능을 제공합니다 .
구문은 다음과 같습니다 ( 이 사이트 에서 뻔뻔스럽게 빌림 ).
#include <iostream>
#include <random>
...
std::tr1::mt19937 eng; // a core engine class
std::tr1::normal_distribution<float> dist;
for (int i = 0; i < 10; ++i)
std::cout << dist(eng) << std::endl;
답변
일부 시스템 (현재 VC 스프링이있는 Windows) RAND_MAX
은 엄청나게 작습니다. 이자형. 15 비트 만 나누면 RAND_MAX
23 개의 가능한 비트 대신 15 비트의 가수 만 생성됩니다. 이것은 문제가 될 수도 있고 아닐 수도 있지만이 경우 일부 값이 누락되었습니다.
아, 방금 그 문제에 대한 의견이 있다는 것을 알았습니다. 어쨌든, 당신을 위해 이것을 해결할 수있는 코드가 있습니다 :
float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);
테스트되지 않았지만 작동 할 수 있습니다 🙂