【问题标题】:Seeding independent bits engine with boosts multiprecision播种独立位引擎,提高多精度
【发布时间】:2020-12-03 22:45:33
【问题描述】:

我有一个简单的拒绝抽样应用程序,它被包装在一个类中并在外部使用,如下面的虚拟示例所示。我能够将 this 帖子改编为 boost::multiprecision 用例。但是我不确定如何适当地为generator 播种,也找不到任何random_device 等效项。

下面的代码“有效”,但如果你快速连续运行多次,你会得到我不想要的相同随机数。还有比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;
}

【问题讨论】:

  • 你有没有想过使用 chrono::steady_clock::now().time_since_epoch().count() 作为种子?例如。你能数毫秒吗?一般来说,我相信 chrono 的时钟比 time() 更精确。

标签: c++ random random-seed boost-multiprecision


【解决方案1】:

这行得通:

#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 的构造函数。本身没有错,但价格昂贵。
  • 您在每次调用时都使用time(NULL) 重新播种生成器。这真的很糟糕;以这种方式,您甚至没有真正获得伪随机序列;您正在使用非递减时钟为生成器播种,并且仅使用出现的第一个值。
  • 您似乎对分发工作的语法感到困惑,因为您对gen() 有类似调用的语法。您正在将可调用对象传递给uniform_real_distribution
  • 您不应该再使用time(NULL) 来播种生成器;我们有更好的rdseed 汇编指令。这就是std::random_device 所说的。

最后,uniform_real_distribution 不是在内部进行拒绝采样吗?那么为什么需要这样做呢?

【讨论】:

  • 谢谢。这基本上就是我想要的;一个“随机”类,可以有效地包装给定的分发类型(在这种情况下为uniform_real),并且可以更灵活地使用。通过拒绝样本,我只是指通过拒绝方法对一些任意“空间”进行抽样。
  • @algae:我明白了;所以你在这里做的拒绝抽样只是一些更复杂目标的替代品
  • 是的。一个小问题:假设dummy 对象被实例化并在多个地方使用。那么,是否可以“全局”修复特定的种子(用于调试),以便对程序的每次调用都给出相同的结果?例如,您可以重载 dummy 构造函数以接受特定的种子,但是您的代码中的每个 dummy 实例都需要更改。
  • 只做一个默认参数:int seed = -1.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-24
相关资源
最近更新 更多