问题描述
我希望能够使用硬件随机数生成器,如果可用,无论是英特尔还是 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 article,entropy()
应该在没有 rdrand 的 cpu 上返回 0,例如 i7-2670qm ivy 桥(我已经在其上测试过 -rdrand 首次出现在其后继产品 Sandy桥),但在 Visual Studio 中始终为 32,如 here 所述。有人建议,缺少随机设备可能会导致 operator()
抛出异常,但这也不会发生。
例如可以使用内在的 int _rdrand32_step (unsigned int* val)
,但它只能从均匀分布中提取,我需要能够利用 C++ 随机库中可用的分布。
在 Visual Studio (2017,2019) 中,将硬件随机数生成器 (rdrand) 与 C++ 的 random
库一起使用的正确方法是什么?
解决方法
在我看来,您应该创建自己的随机数引擎,以供 <random>
中的所有可用发行版使用。
类似的东西
#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
中添加代码进行测试。