在C++ 11/14中有效地生成随机字节数据

Ger*_*ner 13 c++ random distribution c++11

我的要求是生成随机字节的数据(非随机数),也就是统一分布的位.

因此,我想知道使用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;
}
Run Code Online (Sandbox Code Playgroud)

小智 28

你要找的是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));
}
Run Code Online (Sandbox Code Playgroud)

请注意,在一般情况下,接受的答案并不严格正确 - 随机引擎生成属于范围[ min(),max()]的无符号值,这不一定涵盖结果类型的所有可能值(例如std::minstd_rand0::min() == 1),因此您可能会得到如果直接使用引擎则不均匀分布的随机字节.但是,对于std::random_device范围是[ std::numeric_limits<result_type>::min(),std::numeric_limits<result_type>::max()],所以这个特定的引擎也可以在没有适配器的情况下正常工作.

  • 注意:正如@ robert-allan-hennigan-leahy在另一个答案中观察到的那样,`random_bytes_engine`在技术上并不支持`unsigned char`,但这可能是[标准中的缺陷](http://cplusplus.github.io /LWG/lwg-active.html#2326). (2认同)

bam*_*s53 13

分布采用随机位并将其转换为数字.如果你真的想要随机位,那么你想要使用一个引擎:

特别是,这些要求为产生位序列的类型和对象指定算法接口,其中每个可能的位值是均匀可能的.3

对URNG对象的单次调用允许生成并传递许多(通常为32或更多)位,将这些位作为无符号整数类型的单个打包值返回.4 N3847

random_device 碰巧被指定为访问均匀分布的位很容易:

std::random_device engine;
unsigned x = engine(); // sizeof(unsigned) * CHAR_BIT random bits
Run Code Online (Sandbox Code Playgroud)

请注意,其他引擎可能无法使得获得均匀随机位变得非常容易random_device,因为返回的位数少于result_type可以容纳的位数,甚至可以通过有效返回小数位来实现.

如果你担心的是unsigned大小是实现定义的,所以random_device返回一个实现定义的位数,你可以编写一个适配器,在给你之前收集足够的位,或者给你足够的位并缓存其余的位为您的下一个请求.(您也可以这样做来处理其他表现出上述问题的引擎.)


Rob*_*ahy 5

回答你的问题:你不能。

该标准不允许std::uniform_int_distribution进行模板上char,signed char或unsigned char。有人认为这是标准的缺陷,但事实确实如此。

您可以简单地模板std::uniform_int_distributionon unsigned short,并将其最小/最大范围设置为std::numeric_limits<unsigned char>::min()和std::numeric_limits<unsigned char>::max(),然后简单地将结果分配给unsigned char。

从标准:

在本第 26.5 条中,实例化模板的效果:

[...]

e) 具有名为的模板类型参数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. 你可以用 astd::random_device和 a来做到这一点std::seed_seq。

请注意,如果您不使用 astd::seed_seq来播种您的std::mt19937,那么您std::mt19937的内部状态将留下许多许多零,因此需要很长时间才能“热身”。

有关“热身”的更多信息,请参见此处。

  • 我个人会指出未定义的行为,并在否决之前给 Bryan 时间修复它,这不是一个可怕的答案,但这只是我。 (2认同)