添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode . Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).

I need to generate random numbers/ordering. I wish to use the std:: stuff from #include <random> rather than the Qt random functions. I have 3 questions about behaviour/coding.

I have some class of mine into which I wish to put the random functions. I have essentially the following:

// someclass.h
class SomeClass
public:
    int random_int(int range);
    void shuffle(...);
private:
    static std::mt19937 &random_generator();
// someclass.cpp
/*static*/ std::mt19937 &SomeClass::random_generator()
    static std::random_device rd;
    static std::mt19937 gen(rd());
    return gen;
int SomeClass::random_int(int range)
    std::uniform_int_distribution<> distr(0, range);
    return distr(random_generator());
void SomeClass::shuffle(...)
    std::shuffle(..., random_generator());

I have 3 questions:

  • All the examples of shuffling/picking a random are self-contained, they perform the
  • std::random_device rd;
    std::mt19937 gen(rd());
    

    each time any random thingy (shuffle, pick) is wanted, because the example is standalone and does not cover doing more random operations in the future. However I assume one or both of those statements is "slow". That is why I have factored them into function SomeClass::random_generator(), so the generator will be produced once when first called and then re-used in future. Am I right?

    I have implemented that with static function variables. Is this reasonable? If you really want me to use instead, say, a singleton pattern please let me know.

    The return result of my SomeClass::random_generator() is std::mt19937. In random.h that is a typedef mersenne_twister_engine<...> mt19937;. I don't like this as it stands because it uses a specific std::mt19937 type. But other types would be acceptable, e.g. I could change it to mt19937_64 or something else acceptable which isn't even a mersenne_twister_engine<> type. It just has to be usable as parameter to std::shuffle() or std::uniform_int_distribution<>. I cannot spot some "base type" I could use instead as the return result of SomeClass::random_generator() which would allow me to return a std::mt19937 or a std::mt19937_64 or whatever other non-specific types are acceptable. It may be that I need some template definition here? Or what?

    I need to generate random numbers/ordering. I wish to use the std:: stuff from #include <random> rather than the Qt random functions. I have 3 questions about behaviour/coding.

    I have some class of mine into which I wish to put the random functions. I have essentially the following:

    // someclass.h
    class SomeClass
    public:
        int random_int(int range);
        void shuffle(...);
    private:
        static std::mt19937 &random_generator();
    // someclass.cpp
    /*static*/ std::mt19937 &SomeClass::random_generator()
        static std::random_device rd;
        static std::mt19937 gen(rd());
        return gen;
    int SomeClass::random_int(int range)
        std::uniform_int_distribution<> distr(0, range);
        return distr(random_generator());
    void SomeClass::shuffle(...)
        std::shuffle(..., random_generator());
    

    I have 3 questions:

  • All the examples of shuffling/picking a random are self-contained, they perform the
  • std::random_device rd;
    std::mt19937 gen(rd());
    

    each time any random thingy (shuffle, pick) is wanted, because the example is standalone and does not cover doing more random operations in the future. However I assume one or both of those statements is "slow". That is why I have factored them into function SomeClass::random_generator(), so the generator will be produced once when first called and then re-used in future. Am I right?

    I have implemented that with static function variables. Is this reasonable? If you really want me to use instead, say, a singleton pattern please let me know.

    The return result of my SomeClass::random_generator() is std::mt19937. In random.h that is a typedef mersenne_twister_engine<...> mt19937;. I don't like this as it stands because it uses a specific std::mt19937 type. But other types would be acceptable, e.g. I could change it to mt19937_64 or something else acceptable which isn't even a mersenne_twister_engine<> type. It just has to be usable as parameter to std::shuffle() or std::uniform_int_distribution<>. I cannot spot some "base type" I could use instead as the return result of SomeClass::random_generator() which would allow me to return a std::mt19937 or a std::mt19937_64 or whatever other non-specific types are acceptable. It may be that I need some template definition here? Or what?

    Hi @JonB

    Yes std::random is awful !

    For my calculator app, I have implemented a rand function

    // definition
    typedef std::mt19937 RandomGenerator;
    static RandomGenerator& randomGenerator()
        static std::random_device rd;
        static RandomGenerator gen(rd());
        return gen;
    
    // usage
    case ExpFunct::Funct_rand:
    if(val EQ 0)
       ThrowException(ExpException::OutOfRange);
    std::uniform_int_distribution<int> dist(1,val);
    value.setNumber(dist(randomGenerator()));
    break;
    

    Hi @JonB

    Yes std::random is awful !

    For my calculator app, I have implemented a rand function

    // definition
    typedef std::mt19937 RandomGenerator;
    static RandomGenerator& randomGenerator()
        static std::random_device rd;
        static RandomGenerator gen(rd());
        return gen;
    
    // usage
    case ExpFunct::Funct_rand:
    if(val EQ 0)
       ThrowException(ExpException::OutOfRange);
    std::uniform_int_distribution<int> dist(1,val);
    value.setNumber(dist(randomGenerator()));
    break;
    

    You have indeed used static std::random_device rd; static RandomGenerator gen(rd());, so these are only executed once and then re-used. I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted?

    You have used a (static) function with static variables for these, e.g. not a singleton pattern, so you are happy with my version which is the same as yours?

    You have not addressed this. I should not have to make the returned generator be of a type as specific as std::mt19937. This is not required by std::shuffle() or std::uniform_int_distribution<>. They would accept e.g. std::mt19937_64 or other quite different types. But I cannot figure from the header file/CPP reference (https://en.cppreference.com/w/cpp/algorithm/random_shuffle, https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution) what I could write more generically as either a base class or a template definition for the return result of random_generator() which would allow it to return std::mt19937, std::mt19937_64 or other, can you answer that?

    Take for example the definition of std::shuffle():

    template< class RandomIt, class URBG >
    void shuffle( RandomIt first, RandomIt last, URBG&& g );
    

    What can I declare the return-type of random_generator() so as to match the URBG&& g parameter? shuffle() only accepts certain things, e.g. it can't be int or string, so is there a base/common type? Do I have to write my random_generator() function as some kind of template? How/what?

    You have indeed used static std::random_device rd; static RandomGenerator gen(rd());, so these are only executed once and then re-used. I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted?

    You have used a (static) function with static variables for these, e.g. not a singleton pattern, so you are happy with my version which is the same as yours?

    You have not addressed this. I should not have to make the returned generator be of a type as specific as std::mt19937. This is not required by std::shuffle() or std::uniform_int_distribution<>. They would accept e.g. std::mt19937_64 or other quite different types. But I cannot figure from the header file/CPP reference (https://en.cppreference.com/w/cpp/algorithm/random_shuffle, https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution) what I could write more generically as either a base class or a template definition for the return result of random_generator() which would allow it to return std::mt19937, std::mt19937_64 or other, can you answer that?

    Take for example the definition of std::shuffle():

    template< class RandomIt, class URBG >
    void shuffle( RandomIt first, RandomIt last, URBG&& g );
    

    What can I declare the return-type of random_generator() so as to match the URBG&& g parameter? shuffle() only accepts certain things, e.g. it can't be int or string, so is there a base/common type? Do I have to write my random_generator() function as some kind of template? How/what?

    1 I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted?

    This code was writing nearly 10 years ago , so I assume yes :)

    2 same as above

    3 not sure I can help you at this point, I have never used suffle, let's talk more experts than me.

    1 I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted?

    This code was writing nearly 10 years ago , so I assume yes :)

    2 same as above

    3 not sure I can help you at this point, I have never used suffle, let's talk more experts than me.

    , I have never used suffle

    It applies not just to the last parameter to std::shuffle() but equally with uniform_int_distribution<> to the gen parameter in

    std::uniform_int_distribution<> distrib(1, 6);
    std::cout << distrib(gen);
    

    or your use of dist(randomGenerator()) for that. You and I have made that be type std::mt19937, but we shouldn't have to, it works with other types. How can I write that function so that e.g. it might return either a std::mt19937 or a std::mt19937_64?

    Random number generators are a complicated topic. It depends on the context of your application how to handle random numbers. If you just want any sort of randomness (e.g. for games) any of the approaches work.

    However, in a scientific context true uniformity of the generated random numbers is essential. Furthermore, reproducibility of results is also important (this is called Monte Carlo method). Reproducibility is guaranteed by using the same seed every time. Mathematically speaking, only specific seeds are proven to generate a true uniform random number sequence. The last time I have used RNGs C++ didn't have them, yet. So, I have used Tina's RNG: https://www.numbercrunch.de/trng/. Their documentation explains all of this a lot better than I ever could.

    Basically, what I am trying to say is that making your RNG static or not comes down to your use case. Do you need a uniform distribution of random numbers over all your uses of the RNG or not? If you don't care, any approach will do and this discussion is more about performance.

    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct

    Q: What's that?
    A: It's blue light.
    Q: What does it do?
    A: It turns blue.

    Random number generators are a complicated topic. It depends on the context of your application how to handle random numbers. If you just want any sort of randomness (e.g. for games) any of the approaches work.

    However, in a scientific context true uniformity of the generated random numbers is essential. Furthermore, reproducibility of results is also important (this is called Monte Carlo method). Reproducibility is guaranteed by using the same seed every time. Mathematically speaking, only specific seeds are proven to generate a true uniform random number sequence. The last time I have used RNGs C++ didn't have them, yet. So, I have used Tina's RNG: https://www.numbercrunch.de/trng/. Their documentation explains all of this a lot better than I ever could.

    Basically, what I am trying to say is that making your RNG static or not comes down to your use case. Do you need a uniform distribution of random numbers over all your uses of the RNG or not? If you don't care, any approach will do and this discussion is more about performance.

    @SimonSchroeder
    Sorry, but I don't think any part of my questions relate to random numbers or generators or distribution/uniformity performance. They are questions about C++ (especially the as-yet-unanswered question #3). With regard to the static-ness/number of times to call the initial "seeding" when comes with std::random_device rd; std::mt19937 gen(rd()); I only wish to reseed once and then accept the random number which comes from that, as is standard practice with random number generators (e.g. for old-style rand() we used to call srand() just once).