Search code examples
c++boostrandommersenne-twistermultiprecision

Using Boost.Random to generate multiprecision integers from a seed


I am attempting to use the Boost multiprecision libraries for C++ to generate large random numbers. I have been unable to create a generator which is seeded by the time or another random number, so my generator produces the same numbers on every run. How do I seed the generator with a changing value to produce different values on each run? Here is the code which works but produces the same values on each run:

 using namespace boost::multiprecision;
 using namespace boost::random;

 typedef independent_bits_engine<mt19937, 512, mpz_int> generator_type;
 generator_type gen;

 std::cout << gen() << "\n\n";

I have seeded the std mersenne twister before with success:

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 410);
std::cout << dis(gen);

but I am not sure how to seed the multiprecision mt. I get an error if I try to attach any arguments to the generator_type declaration.


Solution

  • Just be sure to include the right headers in the right order. Make sure boost/multiprecision/random.hpp is included before e.g. boost/random.hpp. [1]

    Here's a working sample:

    Live On Coliru

    #include <boost/multiprecision/gmp.hpp>
    #include <boost/multiprecision/random.hpp>
    #include <iostream>
    
    int main() 
    {
        namespace mp = boost::multiprecision;
        using Int = mp::mpz_int;
    
        boost::mt19937 rng(3); // fixing seed for demo
        boost::uniform_int<Int> gen(-pow(Int(2), 400), pow(Int(2), 400));
    
        for (int i=0; i<10; ++i)
            std::cout << gen(rng) << "\n";
    }
    

    Prints:

    -1933652715378833784248363501979652496795524829874743132697181322648247480952527478485970668716806865063045317090084841622
    -1468881213423638668843172777487968633185322950671475476288214928834762957270366851213470028408822700452414112732095789399
    -438410269130756764874038685663894375462191729266787898021001121529040612201593866121171654735148672212107859934777249455
    1640218057904403949431629353470797958943403389857715009204662011172706206212175540336638682612917363014646204359229208161
    2080556950904231221688486212902649050443577133350992840521950777901511719409216800649680002332270542856870490906586634021
    -2462847552934789794366130512379986584363897268428607239076390917679673552257507232435012961043902569359791960286013555735
    1862125165202309929540318106374963238582997665808535945941185531430178511983671609033768595314282085775703389782906055681
    -2252919975572088150601736662143078753669379374770846936106371833826830834376177961242332270710557376868189820866644291936
    986998873018694187216384502983789929097242088320473495018118860428802373488463609060400540575932015408503979156759366945
    111638721010166959954664901006097000984357549061159193446548907668369849648549091048841517202745565156043524728780018634
    

    [1] For rationale see the header:

    namespace boost{ namespace random{ namespace detail{
    //
    // This is a horrible hack: this declaration has to appear before the definition of
    // uniform_int_distribution, otherwise it won't be used...
    // Need to find a better solution, like make Boost.Random safe to use with
    // UDT's and depricate/remove this header altogether.
    //
    template<class Engine, class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
    boost::multiprecision::number<Backend, ExpressionTemplates> 
       generate_uniform_int(Engine& eng, const boost::multiprecision::number<Backend, ExpressionTemplates>& min_value, const boost::multiprecision::number<Backend, ExpressionTemplates>& max_value);
    
    }}}