1

我正在尝试构建一个简单的随机数生成器,但我想确保 random_device 正常工作。我从以下代码开始:

#include <random>
#include <chrono>

class Generator {
public:
    Generator()
        :
        m_DeviceSeed(rd()),
        m_TimeSeed(std::chrono::high_resolution_clock::now().time_since_epoch().count()),
        rng(m_DeviceSeed)
    {
        if (rd.entropy() == 0.0) {
            rng.seed((unsigned)m_TimeSeed);
        }
    }
private:
    //Vars
    std::random_device rd;
    unsigned int m_DeviceSeed;
    unsigned long long m_TimeSeed;
    std::mt19937 rng;
};

我已经看到“std::chrono::high_resolution_clock::now().time_since_epoch().count()”被推荐为 random_device 的替代品,我认为检查熵可以让我将其用作后备;但是,这是用 Visual Studio 编写的,显然这意味着熵总是显示 32,无论它是否正确。

所以,我的问题是:在没有测试熵的情况下播种 std::mt19937 的最可靠方法是什么?chrono 更好还是 random_device 更好?还是某种组合,或完全是其他选择?

基于此:VS2010 中 random_device 的实现?

在大多数情况下,random_device 似乎是播种或生成种子序列的安全选择,但我想确定一下。

4

1 回答 1

2

下班后我花了一些时间深入研究 Microsoft 文档和 VS 源代码,我想我应该分享一下!标题有这个:

_NODISCARD double entropy() const noexcept
    {   // return entropy of random number source
    return (32.0);
    }

_NODISCARD result_type operator()()
    {   // return next value
    return (_Random_device());
    }

第一部分,看起来熵毕竟总是 32.0,操作员调用 _Random_Device。我能够将该定义跟踪到使用 rand_s 的 xrngdev.cpp。

_CRTIMP2_PURE unsigned int __CLRCALL_PURE_OR_CDECL _Random_device()
    {   // return a random value
    unsigned int ans;
    if (_CSTD rand_s(&ans))
        _Xout_of_range("invalid random_device value");
    return (ans);
    }

根据 Microsoft 文档,“rand_s 函数将 0 到 UINT_MAX 范围内的伪随机整数写入输入指针。rand_s 函数使用操作系统生成加密安全随机数。”

此外,跟踪 rand_s.cpp 显示了这一点:

    if (!__acrt_RtlGenRandom(result, static_cast<ULONG>(sizeof(*result))))
{
    errno = ENOMEM;
    return errno;
}

这证实了它使用 RtlGenRandom,如下所示:The implementation of random_device in VS2010?

RtlGenRandom 有点像一个黑盒子,但从发布的内容来看,它使用:

[RtlGenRandom] 按照 FIPS 186-2 附录 3.1 中的规定生成,其中 SHA-1 作为 G 函数。熵来自:

当前进程 ID (GetCurrentProcessID)。

当前线程 ID (GetCurrentThreadID)。

自引导时间以来的滴答计数 (GetTickCount)。

当前时间 (GetLocalTime)。

各种高精度性能计数器(QueryPerformanceCounter)。

用户环境块的 MD4 哈希,包括用户名、计算机名和搜索路径。[...]

高精度内部 CPU 计数器,如 RDTSC、RDMSR、RDPMC

[省略:低级系统信息字段和性能计数器的长列表] [4]

所以是的,std::random_device 似乎是几乎所有 Windows XP 之后的 Windows 应用程序中最强大的选项。

虽然我仍将遵循提供的评论并创建一个 get_seed() 样式函数来生成带有一些额外曲折的完整 std::seed_seq,但这至少回答了我的问题,即 std::random_device 可能是更强大的“基础”播种选项.

于 2020-09-04T06:01:54.980 回答