Эффективная генерация случайных байтов данных в C++11/14
мое требование-генерировать случайные байты данных (не случайных чисел) ака равномерно распределенных битов.
как таковой мне было интересно, каковы правильные / эффективные способы сделать это с помощью случайных объектов c++11/14. Я посмотрел на примеры, но они все кажется, сосредоточиться на генерации чисел (ints, поплавки и т. д.)
текущее решение, которое я использую, следующее:
#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;
}
3 ответов
распределения берут случайные биты и превращают их в числа. Если вы действительно хотите случайные биты, то вы хотите использовать двигатель:
в частности, эти требования определяют алгоритмический интерфейс для типов и объектов, которые производят последовательности битов, в которых каждое возможное битовое значение равномерно вероятно.3
одному вызову объекта URNG разрешено создавать и доставлять много (обычно 32 или более) битов, возвращая эти биты как одно упакованное значение целочисленного типа без знака.4N3847
random_device
бывает указано так, что доступ к равномерно распределенным битам прост:
std::random_device engine;
unsigned x = engine(); // sizeof(unsigned) * CHAR_BIT random bits
обратите внимание, что другие двигатели не могут сделать его так же легко получить равномерно случайные биты, как random_device
, из-за возврата меньшего количества битов, чем их result_type может содержать или даже эффективно возвращать дробные биты.
если ваша забота это unsigned
'ы размер реализации определяется и так random_device
возвращает определенное количество битов реализации, вы можете написать адаптер, который либо собирает достаточное количество битов, прежде чем дать их вам, или тот, который даст вам достаточно битов и кэширует остальные для вашего следующего запроса. (Вы также можете сделать это для обработки других двигателей, которые показывают ранее упомянутые проблемы.)
то, что вы ищете-это 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()
], поэтому этот конкретный двигатель также будет хорошо работать без адаптера.
отвечая на ваш вопрос: Вы не можете.
стандарт не допускает std::uniform_int_distribution
быть шаблоном на char
, signed char
или unsigned char
. Некоторые считают, что это дефект стандарта, но это так.
вы можете просто шаблон std::uniform_int_distribution
on unsigned short
, и установите свой минимальный / максимальный диапазон в std::numeric_limits<unsigned char>::min()
и std::numeric_limits<unsigned char>::max()
, а затем просто назначьте результат unsigned char
.
из стандартного:
на протяжении всего этого подпункта 26.5, эффект создания экземпляра шаблона:
[...]
е) с параметром тип шаблона
IntType
не определено, если соответствующий аргумент шаблона не является CV-неквалифицированным и является одним изshort
,int
,long
,long long
,unsigned short
,unsigned int
,unsigned long
илиunsigned long long
.§26.5.1.1 [rand.запрос.genl]
кроме того:
вы должны использовать std::mt19937
на самом деле создать свой случайные байты. std::random_device
может быть медленным и, вероятно, создает энтропию со статистическими свойствами (т. е. пригодность для использования в криптографии), которые вам не нужны.
что сказал, вам нужно, чтобы семя твое std::mt19937
. Вы можете сделать это с помощью std::random_device
и std::seed_seq
.
обратите внимание, что если вы не используете std::seed_seq
для затравки свой std::mt19937
ваш std::mt19937
останется со многими, многими нулями во внутреннем состоянии, и поэтому он будет принимать его довольно пока "разминка".
для получения дополнительной информации о "разминка", посмотреть здесь.