【问题标题】:Proper usage of RDRAND (on chip generator) as std::random_device with Visual C++'s random library [duplicate]正确使用 RDRAND(片上生成器)作为 std::random_device 与 Visual C++ 的随机库 [重复]
【发布时间】:2021-01-02 14:36:48
【问题描述】:

我希望能够使用硬件随机数生成器,如果可用,并且无论英特尔或 AMD 运行代码,与 C++ 随机库:

void randomDeviceBernouilli(double bernoulliParameter, uint64_t trialCount) {
    std::random_device randomDevice;

    std::cout << "operator():" << randomDevice() << std::endl;
    std::cout << "default random_device characteristics:" << std::endl;
    std::cout << "minimum: " << randomDevice.min() << std::endl;
    std::cout << "maximum: " << randomDevice.max() << std::endl;
    std::cout << "entropy: " << randomDevice.entropy() << std::endl;
    std::bernoulli_distribution bernoulliDist(bernoulliParameter);
    uint64_t trueCount{ 0ull };

    for (uint64_t i = 0; i < trialCount; i++)
        if (bernoulliDist(randomDevice))
            trueCount++;
    std::cout << "Success " << trueCount << " out of " << trialCount << std::endl;
    const double successRate = (double)trueCount / (double)trialCount;
    std::cout << "Empirical: " << std::fixed << std::setprecision(8) << std::setw(10) << successRate << " Theoretical: " << bernoulliParameter << std::endl;
}

根据this articleentropy() 应该在没有 RDRAND 的 cpu 上返回 0,例如 i7-2670qm ivy 桥(我已经在其上测试过 - RDRAND 首次出现在其继任者沙桥中),但是它在 Visual Studio 中始终为 32,如 here 所述。有人建议缺少随机设备可能会导致operator() 抛出异常,但这也不会发生。

例如,可以使用固有的int _rdrand32_step (unsigned int* val),但它只能从均匀分布中提取,我需要能够利用 C++ 随机库中可用的分布。

此外,代码应使用 AMD cpu 上的硬件生成器。

在 Visual Studio(2017、2019)中将硬件随机数生成器 (RDRAND) 与 C++ 的 random 库一起使用的正确方法是什么?

【问题讨论】:

  • msdn 声明 虽然 ISO C++ 标准不要求 random_device 是加密安全的,但在 Visual Studio 中它被实现为加密安全。 但它没有t解释如何。
  • 在后台,VC++ random_device 类仍然使用 rand_s,如下所述:stackoverflow.com/a/9575747/613130
  • @xanatos 这个问题已经过时了,当 Bull Mountain (RDRAND) 首次引入时,必须使用英特尔的库。 8 年后,他们应该找到一种方法将其放入人们希望的标准库中。
  • 检查了通用 C 运行时,它仍在使用RtlGenRandomHere两年前有人看了RtlGenRandom

标签: c++ random visual-c++-2017 rdrand visual-c++-2019


【解决方案1】:

在我看来,您应该创建自己的随机数引擎,该引擎可供&lt;random&gt; 中的所有发行版使用。

类似

#include <exception>
#include <immintrin.h>
#include <iostream>
#include <limits>
#include <ostream>
#include <random>
#include <stdexcept>
#include <string>

using namespace std::string_literals;

class rdrand
{
public:
    using result_type = unsigned int;
    
    static constexpr result_type min() { return std::numeric_limits<result_type>::min(); }
    static constexpr result_type max() { return std::numeric_limits<result_type>::max(); }

    result_type operator()()
    {
        result_type x;
        auto success = _rdrand32_step(&x);

        if (!success)
        {
            throw std::runtime_error("rdrand32_step failed to generate a valid random number");
        }

        return x;
    }
};

int main()
try
{
    auto engine = rdrand();
    auto distribution = std::bernoulli_distribution(0.75);

    // Flip a bias coin with probability of heads = 0.75
    for (auto i = 0; i != 20; ++i)
    {
        auto outcome = distribution(engine);
        std::cout << (outcome ? "heads"s : "tails"s) << std::endl;
    }

    return 0;
}
catch (std::exception const& exception)
{
    std::cerr << "Standard exception thrown with message: \""s << exception.what() << "\""s << std::endl;
}
catch (...)
{
    std::cerr << "Unknown exception thrown"s << std::endl;
}

rdrand 指令是否可用应该在类外部。您可以在main 中添加代码来测试它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-12
    • 2020-01-15
    • 2021-12-18
    • 1970-01-01
    • 2018-06-25
    • 2015-06-27
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多