2. Затем реализуем вспомогательную функцию, которая позволит сопровождать и выводить на экран статистику для каждого типа генераторов случайных чисел. Она принимает два параметра — количество
RD
. Первое, что мы сделаем в этой функции, — определим псевдоним типа для полученного численного типа чисел, возвращаемых генератором. Кроме того, убедимся, что у нас есть как минимум десять сегментов:template
void histogram(size_t partitions, size_t samples)
{
using rand_t = typename RD::result_type;
partitions = max
3. Далее создадим экземпляр генератора типа RD
div
. Все генераторы случайных чисел создают случайные числа в диапазоне от 0
до RD::max()
. Аргумент функции partitions
позволяет вызывающей стороне выбирать, на сколько сегментов мы разделим каждый диапазон случайных чисел. Разделив наибольшее возможное значение на количество сегментов, мы узнаем, насколько большим является каждый из них: RD rd;
rand_t div ((double(RD::max()) + 1) / partitions);
4. Создадим вектор переменных-счетчиков. Он будет иметь размер, равный количеству сегментов. Затем получим случайные значения от генератора в количестве, равном значению переменной samples
rd()
получает случайное число от генератора и изменяет его внутреннее состояние так, чтобы подготовить его к выдаче следующего случайного числа. Разделив каждое случайное число на div
, мы получим номер сегмента, в который оно попадает, и можем увеличить соответствующий счетчик в векторе: vector
for (size_t i {0}; i < samples; ++i) {
++v[rd() / div];
}
5. Теперь у нас есть «аккуратная» гистограмма, содержащая значения-примеры. Чтобы вывести ее на экран, нужно получить более подробную информацию о ее реальных значениях счетчика. Извлечем самое большое значение с помощью алгоритма max_element
100
. Таким образом можно разделить все значения счетчика на max_div
и вывести множество звездочек на консоль, не выходя за значение ширины, равное 100
. Если самое крупное значение меньше 100
(это может произойти в случае применения небольшого количества образцов), то воспользуемся max для получения минимального делителя 1
: rand_t max_elm (*max_element(begin(v), end(v)));
rand_t max_div (max(max_elm / 100, rand_t(1)));
6. Теперь выведем гистограмму на консоль. Каждый сегмент получает собственную строку на консоли. Разделив его значение счетчика на max_div
'*'
, получаем строки гистограммы, которые помещаются в окно консоли: for (size_t i {0}; i < partitions; ++i) {
cout << setw(2) << i << ": "
<< string(v[i] / max_div, '*') << '\n';
}
}
7. О’кей, на этом все. Теперь перейдем к основной программе. Позволим пользователю определить, сколько сегментов и образцов следует применить:
int main(int argc, char **argv)
{
if (argc != 3) {
cout << "Usage: " << argv[0]
<< "
return 1;
}
8. Затем считаем эти переменные из командной строки. Конечно, она содержит строки, которые можно преобразовать в числа с помощью функции std::stoull
stoull
— это аббревиатура для string to unsigned long long, строки к беззнаковым значениям типа long long
): size_t partitions {stoull(argv[1])};
size_t samples {stoull(argv[2])};
9. Теперь вызовем нашу вспомогательную функцию, создающую гистограммы, для
cout << "random_device" << '\n';
histogram
10. Следующий генератор случайных чисел — это default_random_engine
cout << "ndefault_random_engine" << '\n';
histogram