C ++ 11 дает вам много новых опций с random
. Каноническая статья на эту тему будет N3551, Генерация случайных чисел в C ++ 11
Чтобы понять, почему использование rand()
может быть проблематичным, см. rand () Считает вредным презентационный материал Стефан Т. Лававей , данный во время GoingNative 2013 событие. Слайды в комментариях, но вот прямая ссылка 1016 *.
Я также описываю boost
и использование rand
, поскольку устаревший код все еще может требовать его поддержки.
Приведенный ниже пример извлечен из сайта cppreference и использует механизм std :: mersenne_twister_engine и std ::iform_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 ****
Вывод будет зависеть от того, какой дистрибутив вы выберете, поэтому, если мы решили использовать std :: 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 КАК 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC 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 ::iform_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) ) ) ;
}