Эффективная генерация случайных байтов данных в 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 останется со многими, многими нулями во внутреннем состоянии, и поэтому он будет принимать его довольно пока "разминка".

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