播种独立位引擎,提升多精度
Seeding independent bits engine with boosts multiprecision
我有一个简单的拒绝抽样应用程序,它封装在 class 中并在外部使用,如下面的虚拟示例所示。我能够使 this post 适应 boost::multiprecision 用例。但是我不确定如何适当地播种 generator
并且找不到任何 random_device
等效的提升。
下面的代码 'works',但是如果您 运行 快速连续多次使用它,您将获得我不想要的相同随机数。有没有比time(NULL)
更敏感的东西?
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/random.hpp>
using namespace boost::multiprecision; // used only for SO post
using namespace boost::random;
typedef independent_bits_engine<boost::mt19937, std::numeric_limits<cpp_dec_float_50>::digits, cpp_int> generator;
generator &gen()
{
thread_local static generator genny(time(NULL));
return genny;
}
class dummy {
public:
dummy() = default;
cpp_dec_float_50 rejectionSample() {
uniform_real_distribution<cpp_dec_float_50> ur(0,1);
cpp_dec_float_50 x = ur(gen());
while (x > 0.1)
x = ur(gen());
return x;
}
};
int main()
{
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) << std::showpoint;
dummy d;
int nToGet = 5;
for (int i = 0; i < nToGet; ++i)
std::cout << d.rejectionSample() << std::endl;
}
这个有效:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <random>
#include <boost/random.hpp>
using namespace boost::multiprecision;
typedef boost::random::independent_bits_engine<boost::mt19937, std::numeric_limits<cpp_dec_float_50>::digits, cpp_int> generator;
class dummy {
public:
dummy()
{
ur_ = boost::random::uniform_real_distribution<cpp_dec_float_50>(0,1);
std::random_device rd;
gen_ = generator(rd());
ur_(gen_);
}
cpp_dec_float_50 rejectionSample() {
cpp_dec_float_50 x = ur_(gen_);
while (x > 0.1)
{
x = ur_(gen_);
}
return x;
}
private:
boost::random::uniform_real_distribution<cpp_dec_float_50> ur_;
generator gen_;
};
int main()
{
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) << std::showpoint;
dummy d;
int nToGet = 50;
for (int i = 0; i < nToGet; ++i) {
std::cout << d.rejectionSample() << std::endl;
}
}
所以你的误解是:
- 您在每次调用时都调用了
uniform_real_distribution
的构造函数。本身没有错,但是很贵。
- 您是 re-seeding 每次通话的生成器,
time(NULL)
。那真的很糟糕;那样你甚至都没有得到一个伪随机序列;您正在使用 non-decreasing 时钟为生成器提供种子并且仅使用出现的第一个值。
- 您似乎对分布的工作语法感到困惑,因为您对
gen()
使用了 call-like 语法。您正在 将可调用 传递给 uniform_real_distribution
。
- 您不应该再使用
time(NULL)
作为种子生成器;我们有更好的 rdseed
汇编指令。这就是所谓的std::random_device
.
最后,uniform_real_distribution
不在内部进行拒绝抽样吗?那你为什么需要这样做?
我有一个简单的拒绝抽样应用程序,它封装在 class 中并在外部使用,如下面的虚拟示例所示。我能够使 this post 适应 boost::multiprecision 用例。但是我不确定如何适当地播种 generator
并且找不到任何 random_device
等效的提升。
下面的代码 'works',但是如果您 运行 快速连续多次使用它,您将获得我不想要的相同随机数。有没有比time(NULL)
更敏感的东西?
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/random.hpp>
using namespace boost::multiprecision; // used only for SO post
using namespace boost::random;
typedef independent_bits_engine<boost::mt19937, std::numeric_limits<cpp_dec_float_50>::digits, cpp_int> generator;
generator &gen()
{
thread_local static generator genny(time(NULL));
return genny;
}
class dummy {
public:
dummy() = default;
cpp_dec_float_50 rejectionSample() {
uniform_real_distribution<cpp_dec_float_50> ur(0,1);
cpp_dec_float_50 x = ur(gen());
while (x > 0.1)
x = ur(gen());
return x;
}
};
int main()
{
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) << std::showpoint;
dummy d;
int nToGet = 5;
for (int i = 0; i < nToGet; ++i)
std::cout << d.rejectionSample() << std::endl;
}
这个有效:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <random>
#include <boost/random.hpp>
using namespace boost::multiprecision;
typedef boost::random::independent_bits_engine<boost::mt19937, std::numeric_limits<cpp_dec_float_50>::digits, cpp_int> generator;
class dummy {
public:
dummy()
{
ur_ = boost::random::uniform_real_distribution<cpp_dec_float_50>(0,1);
std::random_device rd;
gen_ = generator(rd());
ur_(gen_);
}
cpp_dec_float_50 rejectionSample() {
cpp_dec_float_50 x = ur_(gen_);
while (x > 0.1)
{
x = ur_(gen_);
}
return x;
}
private:
boost::random::uniform_real_distribution<cpp_dec_float_50> ur_;
generator gen_;
};
int main()
{
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10) << std::showpoint;
dummy d;
int nToGet = 50;
for (int i = 0; i < nToGet; ++i) {
std::cout << d.rejectionSample() << std::endl;
}
}
所以你的误解是:
- 您在每次调用时都调用了
uniform_real_distribution
的构造函数。本身没有错,但是很贵。 - 您是 re-seeding 每次通话的生成器,
time(NULL)
。那真的很糟糕;那样你甚至都没有得到一个伪随机序列;您正在使用 non-decreasing 时钟为生成器提供种子并且仅使用出现的第一个值。 - 您似乎对分布的工作语法感到困惑,因为您对
gen()
使用了 call-like 语法。您正在 将可调用 传递给uniform_real_distribution
。 - 您不应该再使用
time(NULL)
作为种子生成器;我们有更好的rdseed
汇编指令。这就是所谓的std::random_device
.
最后,uniform_real_distribution
不在内部进行拒绝抽样吗?那你为什么需要这样做?