Трябва ли произволните разпределения да се предават по референция или да бъдат членове на обекти в c++

Ако приемем, че създаваме само по-малко от 20 обекта от клас Blob и по отношение на ефективността (времево изпълнение) и проблеми с управлението на паметта, има ли най-добрият вариант между:

  • Задаване на произволния генератор и генерираните дистрибуции като частни членове на класа като:

    class Blob {
    private:
    std::mt19937 engine;
    std::uniform_real_distribution<double> R_distribution;
    std::binomial_distribution<int> B_distribution;
    }
    

    и използването им директно в Blob методи. Така, когато извикваме разпределение, ние също променяме състоянието на двигателя, който е член.

  • Или задаване на произволния генератор като член на частен клас и предаване на разпределенията чрез препратка към методите? Например:

    class Blob {
    private:
    std::mt19937 engine; //engine
    }
    
    void Blob::run() {
    int blabla = 10;
    std::uniform_real_distribution<double> R_distribution(0, 10);
    do_something(blabla, R_distribution);
    ...
    }
    

Докато преминаването по референция предизвиква по-ниски режийни разходи като цяло, има ли значение в този случай по-специално? Как се мащабира общият въпрос, когато извиквате разпределенията огромен брой пъти (10^9 или повече)?


person Grasshoper    schedule 05.01.2018    source източник
comment
Бих се изкушил да направя специален клас генератор на произволни числа, да създам един обект и да предам препратка към него на всеки друг клас, който се нуждае от произволни числа. Или, по-вероятно, глобална функция за произволни числа с локален статичен генератор и разпределение на нишката. Но много зависи от ситуацията, така че мисля, че това е малко широко или базирано на мнение tbh.   -  person Galik    schedule 05.01.2018
comment
Звучи, че ще бъде много лесно да го тествате сами с няколко цикъла и 2 тестови класа. Няма нужда да се спекулира.   -  person super    schedule 05.01.2018
comment
@супер сигурен! Но се чудя как се променя експоненциалната скорост на времето за изпълнение за двете решения за много големи обаждания и дори по-големи обаждания. Това означава, че трябва да тествам за тези големи обаждания и може да отнеме много (изпълнение) време.   -  person Grasshoper    schedule 05.01.2018
comment
Проблемът с двигателя, споделен между нишките, е твърде много процесорно време, изразходвано за синхронизиране на вътрешното състояние на двигателя. Ако се изисква висока производителност, имате нужда от отделен двигател за всяка нишка. Обектите за разпространение не са проблем. Имайте предвид, че не се нуждаете от най-доброто решение, а от достатъчно добро.   -  person Dialecticus    schedule 05.01.2018
comment
@Dialecticus Благодаря ви за приноса! Задаването на един двигател на нишка определено е опция, ако приемем, че искаме нещо приемливо по отношение на времето за изпълнение.   -  person Grasshoper    schedule 05.01.2018


Отговори (2)


Разпределенията са евтини и могат да бъдат създадени/изхвърлени, когато искате. Двигателите не са. В идеалния случай трябва да инициализирате своя PRNG само веднъж и да се уверите, че е thread_local, ако програмата ви е многонишкова. PRNG като std::mt19937 са обемисти и имат голямо вътрешно състояние. Помислете да направите нещо подобно:

inline auto global_rng() -> std::mt19937& {
    thread_local std::mt19937 e{ get_seed() };
    return e;
}

void foo() {
    thread_local std::uniform_real_distribution<double> d; 
    // ...
}
person user6320840    schedule 05.01.2018
comment
@HolyBlackCat thread_local предполага static. Но все пак редактиран. - person user6320840; 05.01.2018
comment
uniform_real_distribution може да е евтино, но AFAIK нищо в стандарта не предполага, че всички дистрибуции могат да бъдат създадени/изхвърлени волю или неволю... това трябва да се реши на базата на клас на разпределение (вероятно след известно профилиране) - person Massimiliano Janes; 05.01.2018

Преди известно време бях направил набор от обвиващи класове, за да обхвана повечето от генераторите на случайни числа на std, двигателите, началните типове и дистрибуциите, за да работят безпроблемно заедно. Вие сте свободни да използвате този клас и можете да го промените, за да отговаря на вашите собствени нужди, ако желаете. Тук е само заглавният клас и всички функции са декларирани като статични. Конструкторите са защитени по подразбиране. Не можете да създадете екземпляр на тези класове. Има 2 класа: RandomEngine и RandomDistribution. За да направя живота малко по-лесен след двата класа, създадох 2 typedefs, за да съкратя количеството на писане, докато ги използвам, съответно RE и RD. Има няколко набора от enums в тези класове, само един от тях се използва директно, другите 2 са там само за визуална справка, но потребителят може да ги използва, ако е необходимо. Ето класовете само в заглавен файл.


RandomGenerator.h

#ifndef RANDOM_GENERATOR_H
#define RANDOM_GENERATOR_H

#include <limits>
#include <chrono>
#include <random>

// ----------------------------------------------------------------------------
// Class RandomEngine { typedef = RE }
class RandomEngine {
public:
    using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock>;

    // Used To Determine Which Seeding Process To Use
    enum SeedType {
        USE_CHRONO_CLOCK,
        USE_RANDOM_DEVICE,
        USE_SEED_VALUE, 
        USE_SEED_SEQ,
    }; // SeedType

    // This Enum Is Not In Use - It Is A Visual Reference Only; But If User Wants To
    // Use It For Their Own Pupose They Are Free To Do So.
    enum EngineType {
        // Default Random Engine
        DEFAULT_RANDOM_ENGINE,

        // Linear Congruential Engines
        MINSTD_RAND0,
        MINSTD_RAND,

        // Mersenne Twister Engines 
        MT19937,
        MT19937_64,

        // Subtract With Carry Engines 
        RANLUX24_BASE,
        RANLUX48_BASE,

        // Discard Block Engines 
        RANLUX24,
        RANLUX48,

        // Shuffle Order Engines
        KNUTH_B,

    }; // EngineType

protected:
    RandomEngine() = default;

    // Internal Helper Function  
    // ---------------------------------------------------------------------------
    // getRandomDevice()
    static std::random_device& getRandomDevice() {
        static std::random_device device{};
        return device;
    } // getRandomDevice

public:
    // ---------------------------------------------------------------------------
    // getTimeNow()
    static unsigned int getTimeNow() {
        unsigned int now = static_cast<unsigned int>(Clock::now().time_since_epoch().count());
        return now;
    } // getTimeNow

    // ---------------------------------------------------------------------------
    // getDefaultRandomEngine()
    static std::default_random_engine& getDefaultRandomEngine( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::default_random_engine engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getDefaultRandomEngine

    // ---------------------------------------------------------------------------
    // getMinStd_Rand0()
    static std::minstd_rand0& getMinStd_Rand0( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::minstd_rand0 engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getMinStd_Rand0

    // ---------------------------------------------------------------------------
    // getMinStd_Rand()
    static std::minstd_rand& getMinStd_Rand( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::minstd_rand engine{};

        switch( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed(seq);
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getMinStd_Rand

    // ---------------------------------------------------------------------------
    // getMt19937()
    static std::mt19937& getMt19937( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::mt19937 engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } //getMt19937

    // ---------------------------------------------------------------------------
    // getMt19937_64()
    static std::mt19937_64& getMt19937_64( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::mt19937_64 engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getMt19937_64

    // ---------------------------------------------------------------------------
    // getRanLux24_base()
    static std::ranlux24_base& getRanLux24_base( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::ranlux24_base engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getRanLux24_base

    // ---------------------------------------------------------------------------
    // getRanLux48_base()
    static std::ranlux48_base& getRanLux48_base( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::ranlux48_base engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getRanLux48_base

    // ---------------------------------------------------------------------------
    // getRanLux24()
    static std::ranlux24& getRanLux24( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::ranlux24 engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } // getRanLux24

    // ---------------------------------------------------------------------------
    // getRanLux48()
    static std::ranlux48& getRanLux48( SeedType type, unsigned seedValue = 0, std::seed_seq& seq = std::seed_seq{} ) {
        static std::ranlux48 engine{};

        switch ( type ) {
            case USE_CHRONO_CLOCK: {
                engine.seed( getTimeNow() );
                break;
            }
            case USE_SEED_VALUE: {
                engine.seed( seedValue );
                break;
            }
            case USE_SEED_SEQ: {
                engine.seed( seq );
                break;
            }
            default: {
                engine.seed( getRandomDevice()() );
                break;
            }
        }

        return engine;
    } //getRanLux48

private:

}; // RandomEngine

// ----------------------------------------------------------------------------
// Class - RandomDistrubtion { typedef = RD }
class RandomDistribution {
public:
    // This Enum Is Not In Use - It Is A Visual Reference Only; But If User Wants To
    // Use It For Their Own Pupose They Are Free To Do So.
    enum DistributionType {
        // Uniform Distributions
        UNIFORM_INT,
        UNIFORM_INT_DISTRIBUTION,
        UNIFORM_REAL,
        UNIFORM_REAL_DISTRIBUTION,
        // GENERATE_CANONICAL, - This is a function template and not a class template use it directly form std:: <random> c++11

        // Bernoulli Distributions
        BERNOULLI_DISTRIBUTION,
        BINOMAIL_DISTRIBUTION,
        NEGATIVE_BINOMIAL_DISTRIBUTION,
        GEOMETRIC_DISTRIBUTION,

        // Poisson Distributions
        POISSON_DISTRIBUTION,
        EXPONENTIAL_DISTRIBUTION,
        GAMMA_DISTRIBUTION,
        WEIBULL_DISTRIBUTION,
        EXTREME_VALUE_DISTRIBUTION,

        // Normal Distributions
        NORMAL_DISTRIBUTION,
        LOGNORMAL_DISTRIBUTION,
        CHI_SQUARED_DISTRIBUTION,
        CAUCHY_DISTRIBUTION,
        FISHER_F_DISTRIBUTION,
        STUDENT_T_DISTRIBUTION,

        // Sampling Distributions
        DISCRETE_DISTRIBUTION,
        PIECEWISE_CONSTANT_DISTRIBUTION,
        PIECEWISE_LINEAR_DISTRIBUTION
    }; // DistributionType

protected:
    RandomDistribution() = default;

public:

    // UNIFORM DISTRIBUTIONS

    // ---------------------------------------------------------------------------
    // getUniformIntDistribution()
    template<class IntType = int>
    static std::uniform_int_distribution<IntType>& getUniformIntDistribution( IntType lowerBound = 0, IntType upperBound = (std::numeric_limits<IntType>::max)() ) {
        static std::uniform_int_distribution<IntType> dist( lowerBound, upperBound );
        return dist;
    } // getUniformIntDistribution

    // ---------------------------------------------------------------------------
    // getUniformRealDistribution()
    template<class RealType = double>
    static std::uniform_real_distribution<RealType>& getUniformRealDistribution( RealType lowerBound = 0.0, RealType upperBound = 1.0 ) {
        static std::uniform_real_distribution<RealType> dist( lowerBound, upperBound );
        return dist;
    } // getUniformRealDistribution



    // BERNOULLI DISTRIBUTIONS

    // ---------------------------------------------------------------------------
    // getBernoulliDistribution()
    static std::bernoulli_distribution& getBernoulliDistribution( double probability = 0.5 ) {
        static std::bernoulli_distribution dist( probability );
        return dist;
    } // getBernoulliDistribution

    // ---------------------------------------------------------------------------
    // getBinomialDistribution()
    template<class IntType = int>
    static std::binomial_distribution<IntType>& getBinomialDistribution( IntType numTrials = 1, double probability = 0.5 ) {
        static std::binomial_distribution<IntType> dist( numTrials, probability );
        return dist;
    } // getBinomialDistribution

    // ---------------------------------------------------------------------------
    // getNegativeBinomialDistribution()
    template<class IntType = int>
    static std::negative_binomial_distribution<IntType>& getNegativeBinomialDistribution( IntType numTrialFailures = 1, double probability = 0.5 ) {
        static std::negative_binomial_distribution<IntType> dist( numTrialFailures, probability );
        return dist;
    } // getNegativeBinomialDistribution

    // ---------------------------------------------------------------------------
    // getGeometricDistribution()
    template<class IntType = int>
    static std::geometric_distribution<IntType>& getGeometricDistribution( double probability = 0.5 ) {
        static std::geometric_distribution<IntType> dist( probability ); 
        return dist;
    } // getGeometricDistribution



    // POISSON DISTRIBUTIONS

    // ---------------------------------------------------------------------------
    // getPoissonDistribution()
    template<class IntType = int>
    static std::poisson_distribution<IntType>& getPoissonDistribution( double mean = 1.0 ) {
        static std::poisson_distribution<IntType> dist( mean );
        return dist;
    } // getPoissonDistribution

    // ---------------------------------------------------------------------------
    // getExponentialDistribution()
    template<class RealType = double>
    static std::exponential_distribution<RealType>& getExponentialDistribution( RealType rate = 1.0 ) {
        static std::exponential_distribution<RealType> dist( rate );
        return dist;
    } // getExponentialDistribution

    // ---------------------------------------------------------------------------
    // getGammDistribution()
    template<class RealType = double>
    static std::gamma_distribution<RealType>& getGammaDistribution( RealType alpha_shape = 1.0, RealType beta_scale = 1.0 ) {
        static std::gamma_distribution<RealType> dist( alpha_shape, beta_scale );
        return dist;
    } // getGammaDistribution

    // ---------------------------------------------------------------------------
    // getWeibullDistribution()
    template<class RealType = double>
    static std::weibull_distribution<RealType>& getWeibullDistribution( RealType alpha_shape = 1.0, RealType beta_scale = 1.0 ) {
        static std::weibull_distribution<RealType> dist( alpha_shape, beta_scale );
        return dist;
    } // getWeibullDistribution

    // ---------------------------------------------------------------------------
    // getExtremeValueDistribution()
    template<class RealType = double>
    static std::extreme_value_distribution<RealType>& getExtremeValueDistribution( RealType location = 0.0, RealType scale = 1.0 ) {
        static std::extreme_value_distribution<RealType> dist( location, scale );
        return dist;
    } // getExtremeValueDistribution


    // NORMAL DISTRIBUTIONS

    // ---------------------------------------------------------------------------
    // getNormalDistribution()
    template<class RealType = double>
    static std::normal_distribution<RealType>& getNormalDistribution( RealType mean = 0.0, RealType stddev = 1.0 ) {
        static std::normal_distribution<RealType> dist( mean, stddev );
        return dist;
    } // getNormaDistribution

    // ---------------------------------------------------------------------------
    // getLogNormalDistribution()
    template<class RealType = double>
    static std::lognormal_distribution<RealType>& getLogNormalDistribution( RealType logScale = 0.0, RealType shape = 1.0 ) {
        static std::lognormal_distribution<RealType> dist( logScale, shape );
        return dist;
    } // getLogNormalDistribution

    // ---------------------------------------------------------------------------
    // getChiSquaredDistribution()
    template<class RealType = double>
    static std::chi_squared_distribution<RealType>& getChiSquaredDistribution( RealType degreesOfFreedom = 1.0 ) {
        static std::chi_squared_distribution<RealType> dist( degreesOfFreedom );
        return dist;
    } // getChiSquaredDistribution

    // ---------------------------------------------------------------------------
    // getCauchyDistribution()
    template<class RealType = double>
    static std::cauchy_distribution<RealType>& getCauchyDistribution( RealType location = 0.0, RealType scale = 1.0 ) {
        static std::cauchy_distribution<RealType> dist( location, scale );
        return dist;
    } // getCauchyDistribution

    // ---------------------------------------------------------------------------
    // getFisherFDistribution() Both m,n are degress of freedom
    template<class RealType = double>
    static std::fisher_f_distribution<RealType>& getFisherFDistribution( RealType m = 1.0, RealType n = 1.0 ) {
        static std::fisher_f_distribution<RealType> dist( m, n );
        return dist;
    } // getFisherFDistribution

    // ---------------------------------------------------------------------------
    // getStudentTDistribution()
    template<class RealType = double>
    static std::student_t_distribution<RealType>& getStudentTDistribution( RealType degreesOfFreedom = 1.0 ) {
        static std::student_t_distribution<RealType> dist( degreesOfFreedom );
        return dist;
    } // getStudentTDistribution


    // SAMPLING DISTRIBUTIONS

    // ---------------------------------------------------------------------------
    //  getDiscreteDistribution()
    template<class IntType = int>
    static std::discrete_distribution<IntType>& getDiscreteDistribution() {
        static std::discrete_distribution<IntType> dist;
        return dist;
    } // getDiscreteDistribution

    // ---------------------------------------------------------------------------
    //  getDiscreteDistribution()
    template<class IntType = int, class InputIt>
    static std::discrete_distribution<IntType>& getDiscreteDistribution( InputIt first, InputIt last ) {
        static std::discrete_distribution<IntType> dist( first, last );
        return dist;
    } // getDiscreteDistribution

    // ---------------------------------------------------------------------------
    //  getDiscreteDistribution()
    template<class IntType = int>
    static std::discrete_distribution<IntType>& getDiscreteDistribution( std::initializer_list<double> weights ) {
        static std::discrete_distribution<IntType> dist( weights );
        return dist;
    } // getDiscreteDistribution

    // ---------------------------------------------------------------------------
    //  getDiscreteDistribution()
    template<class IntType = int, class UnaryOperation>
    static std::discrete_distribution<IntType>& getDiscreteDistribution( std::size_t count, double xmin, double xmax, UnaryOperation unary_op ) {
        static std::discrete_distribution<IntType> dist( count, xmin, xmax, unary_op );
        return dist;
    } // getDiscreteDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseConstantDistribution()
    template<class RealType = double>
    static std::piecewise_constant_distribution<RealType>& getPiecewiseConstantDistribution() {
        static std::piecewise_constant_distribution<RealType> dist;
        return dist;
    } // getPiecewiseConstantDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseConstantDistribution()
    template<class RealType = double, class InputIt1, class InputIt2>
    static std::piecewise_constant_distribution<RealType>& getPiecewiseConstantDistribution( InputIt1 first_i, InputIt1 last_i, InputIt2 first_w ) {
        static std::piecewise_constant_distribution<RealType> dist( first_i, last_i, first_w );
        return dist;
    } // getPiecewiseConstantDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseConstantDistribution()
    template<class RealType = double, class UnaryOperation>
    static std::piecewise_constant_distribution<RealType>& getPiecewiseConstantDistribution( std::initializer_list<RealType> bl, UnaryOperation fw ) {
        static std::piecewise_constant_distribution<RealType> dist( bl, fw );
        return dist;
    } // getPiecewiseConstantDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseConstantDistribution()
    template<class RealType = double, class UnaryOperation>
    static std::piecewise_constant_distribution<RealType>& getPiecewiseConstantDistribution( std::size_t nw, RealType xmin, RealType xmax, UnaryOperation fw ) {
        static std::piecewise_constant_distribution<RealType> dist( nw, xmin, xmax, fw );
        return dist;
    } // getPiecewiseConstantDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseLinearDistribution()
    template<class RealType = double>
    static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution() {
        static std::piecewise_linear_distribution<RealType> dist;
        return dist;
    } // getPiecewiseLinearDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseLinearDistribution()
    template<class RealType = double, class InputIt1, class InputIt2>
    static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( InputIt1 first_i, InputIt1 last_i, InputIt2 first_w ) {
        static std::piecewise_linear_distribution<RealType> dist( first_i, last_i, first_w );
        return dist;
    } // getPiecewiseLinearDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseLinearDistribution()
    template<class RealType = double, class UnaryOperation>
    static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( std::initializer_list<RealType> bl, UnaryOperation fw ) {
        static std::piecewise_linear_distribution<RealType> dist( bl, fw );
        return dist;
    } // getPiecewiseLinearDistribution

    // ---------------------------------------------------------------------------
    // getPiecewiseLinearDistribution()
    template<class RealType = double, class UnaryOperation>
    static std::piecewise_linear_distribution<RealType>& getPiecewiseLinearDistribution( std::size_t nw, RealType xmin, RealType xmax, UnaryOperation fw ) {
        static std::piecewise_linear_distribution<RealType> dist( nw, xmin, xmax, fw );
        return dist;
    } // getPiecewiseLinearDistribution

}; // RandomDistribution

typedef RandomEngine RE;
typedef RandomDistribution RD;

#endif // !RANDOM_GENERATOR_H

И човек би използвал този клас като такъв, който може да се види в тези няколко примера по-долу.

main.cpp

#include <sstream>
#include <iostream>
#include "RandomGenerator.h"

int main() {        
    std::ostringstream strStream;
    strStream << "Random number generated between [0.0, 1.0] \nusing mersenne & chrono clock for seeding:\n";
    std::cout << strStream.str();

    std::uniform_real_distribution<double> urd = RD::getUniformRealDistribution<double>( 0.0, 1.0 );
    for ( unsigned i = 1; i <= 50; i++ ) {
        std::ostringstream strStream;
        double val = urd( RE::getMt19937( RE::SeedType::USE_CHRONO_CLOCK, 12 ) );
        strStream << i << " : " << val << "\n";
        std::cout << strStream.str();
    }
    std::cout << std::endl;

    strStream.clear();
    //std::ostringstream strStream;
    strStream << "Random number generated Between [1,9] using default random engine & uniform int distribution is: " << std::endl;
    std::cout << strStream.str();

    std::uniform_int_distribution<unsigned> uid = RD::getUniformIntDistribution<unsigned>( 1, 9 );
    // std::uniform_int_distribution<unsigned> uid( 1, 9 );
    for ( unsigned int i = 1; i < 101; i++ ) {
        std::ostringstream strStream;
        unsigned val = uid( RE::getDefaultRandomEngine( RE::SeedType::USE_CHRONO_CLOCK, 14 ) );

        strStream << i << " : " << val << std::endl;
        std::cout << strStream.str();
    }    
    std::cout << std::endl;

    for ( unsigned int i = 1; i < 101; i++ ) {
        std::ostringstream strStream;
        // Using the same distribution above but reseeding it with a different type of seeding method.
        unsigned val = uid( RE::getDefaultRandomEngine( RE::SeedType::USE_RANDOM_DEVICE ) );

        strStream << i << " : " << val << std::endl;
        std::cout << strStream.str();
    }

    std::cout << "\nPress any key and enter to quit." << std::endl;
    char q;
    std::cin >> q;
    return 0;
}

Тези класове автоматично ще декларират, настройват и извикват генераторите и дистрибуциите, като използват статичните методи с параметрите, които изискват. Ако имате нужда те да бъдат локални за нишки, не би трябвало да е проблем да промените това според вашите нужди.

Обикновено как използвам това е това, което класът се нуждае от произволно разпределение. Ще включа тази заглавка, след това ще имам членска променлива от тип разпределение, от който се нуждая, и ще го задам, като използвам желания генератор и изискван механизъм за тип зареждане.

Ако имате някакви въпроси, моля не се колебайте да попитате.

person Francis Cugler    schedule 05.01.2018
comment
Уау! Благодаря ви за такъв принос! - person Grasshoper; 05.01.2018