Эффективное генерирование случайных байтов данных в C ++ 11/14

Мое требование — генерировать случайные байты данных. (не случайные числа) ака равномерно распределенные биты.

В связи с этим мне было интересно, каковы правильные / эффективные способы сделать это с помощью случайных средств C ++ 11/14. Я посмотрел на примеры, но они все кажется, сосредоточиться на генерации чисел (целые, плавающие и т. д.)

Текущее решение, которое я использую, заключается в следующем:

#include <vector>
#include <random>

int main()
{
std::random_device rd;
std::uniform_int_distribution<int> dist(0,255);
std::vector<char> data(1000);
for (char& d : data)
{
d = static_cast<char>(dist(rd) & 0xFF);
}
return 0;
}

11

Решение

Распределения берут случайные биты и превращают их в числа. Если вы действительно хотите случайные биты, то вы хотите использовать движок:

В частности, эти требования определяют алгоритмический интерфейс для типов и объектов, которые создают последовательности битов, в которых каждое возможное значение бита является одинаково вероятным.3

Один вызов объекта URNG позволяет производить и доставлять много (обычно 32 или более) битов, возвращая эти биты как единое упакованное значение целого типа без знака.4
N3847

random_device бывает так, что доступ к равномерно распределенным битам прост:

std::random_device engine;
unsigned x = engine(); // sizeof(unsigned) * CHAR_BIT random bits

Обратите внимание, что другие движки могут не так легко получить равномерно случайные биты, как random_deviceиз-за возврата меньшего количества битов, чем может содержать их result_type, или даже путем эффективного возврата дробных битов.

Если вы обеспокоены тем, что unsignedРазмер определяется реализацией и так random_device возвращает число битов, определенное реализацией, вы можете написать адаптер, который либо собирает достаточно битов, прежде чем отдать их вам, либо адаптер, который даст вам достаточно битов и кеширует остальное для вашего следующего запроса. (Вы можете также сделать это, чтобы обращаться с другими двигателями, которые показывают ранее упомянутые проблемы.)

14

Другие решения

То, что вы ищете, это std::independent_bits_engine адаптер:

#include <vector>
#include <random>
#include <climits>
#include <algorithm>
#include <functional>

using random_bytes_engine = std::independent_bits_engine<
std::default_random_engine, CHAR_BIT, unsigned char>;

int main()
{
random_bytes_engine rbe;
std::vector<unsigned char> data(1000);
std::generate(begin(data), end(data), std::ref(rbe));
}

Обратите внимание, что принятый ответ не является строго правильным в общем случае — случайные механизмы выдают значения без знака, принадлежащие диапазону [min(), max()], который не обязательно охватывает все возможные значения типа результата (например, std::minstd_rand0::min() == 1) и, таким образом, вы можете получить случайные байты, которые распределены неравномерно, если использовать движок напрямую. Однако для std::random_device диапазон [std::numeric_limits<result_type>::min(), std::numeric_limits<result_type>::max()], так что этот конкретный двигатель также будет работать без адаптера.

23

Чтобы ответить на ваш вопрос: вы не можете.

Стандарт не позволяет std::uniform_int_distribution быть шаблонным на char, signed char, или же unsigned char, Некоторые считают, что это дефект в стандарте, но это так.

Вы можете просто шаблон std::uniform_int_distribution на unsigned shortи установите его минимальный / максимальный диапазон на std::numeric_limits<unsigned char>::min() а также std::numeric_limits<unsigned char>::max(), а затем просто присвойте результат unsigned char,

Из стандарта:

На протяжении этого подпункта 26.5 эффект создания шаблона:

[…]

е) который имеет параметр типа шаблона с именем IntType не определено, если соответствующий аргумент шаблона не является cv-unqualified и не является одним из short, int, long, long long, unsigned short, unsigned int, unsigned long, или же unsigned long long,

§26.5.1.1 [rand.req.genl]

Более того:

Вы должны использовать std::mt19937 на самом деле генерировать ваши случайные байты. std::random_device может быть медленным и, вероятно, приводит к энтропии со статистическими свойствами (т.е. пригодностью для использования в криптографии), которые вам не нужны.

Тем не менее, вам нужно будет посеять std::mt19937, Вы можете сделать это с std::random_device и std::seed_seq.

Обратите внимание, что если вы не используете std::seed_seq посеять std::mt19937, ваш std::mt19937 останется со многими, многими нулями во внутреннем состоянии, и поэтому потребуется много времени, чтобы «прогреться».

Для получения дополнительной информации о «разминке», посмотреть здесь.

4
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector