What is performance-wise the best way to generate random bools?

前端 未结 9 2174
滥情空心
滥情空心 2020-12-23 21:14

I need to generate random Boolean values on a performance-critical path.

The code which I wrote for this is

std::random_device   rd;
std::uniform_int         


        
相关标签:
9条回答
  • 2020-12-23 22:06

    If performance is your only criterion, then the answer is:

    bool get_random()
    {
        return true; // chosen by fair coin flip.
                     // guaranteed to be random.
    }
    

    Unfortunately, the entropy of this random number is zero, but the performance is quite fast.

    Since I suspect that this random number generator is not very useful to you, you will need to quantify how random you want your booleans to be. How about a cycle length of 2048? One million? 2^19937-1? Until the end of the universe?

    I suspect that, since you explicitly stated that performance is your utmost concern, then a good old fashioned linear congruential generator might be "good enough". Based on this article, I'm guessing that this generator's period is around 32*((2^31)-5), or about 68 trillion iterations. If that's not "good enough", you can drop in any C++11 compatible generator you like instead of minstd_rand.

    For extra credit, and a small performance hit, modify the below code to use the biased coin algorithm to remove bias in the generator.

    #include <iostream>
    #include <random>
    
    bool get_random()
    {
        typedef std::minstd_rand generator_type;
        typedef generator_type::result_type result_type;
    
        static generator_type generator;
        static unsigned int bits_remaining = 0;
        static result_type random_bits;
    
        if ( bits_remaining == 0 )
        {
            random_bits = generator();
            bits_remaining = sizeof( result_type ) * CHAR_BIT - 1;
        }
    
        return ( ( random_bits & ( 1 << bits_remaining-- ) ) != 0 );
    }
    
    int main()
    {
        for ( unsigned int i = 0; i < 1000; i++ )
        {
            std::cout << " Choice " << i << ": ";
            if ( get_random() )
                std::cout << "true";
            else
                std::cout << "false";
    
            std::cout << std::endl;
        }
    }
    
    0 讨论(0)
  • 2020-12-23 22:16

    A way would be to just generate a unsigned long long for every 64 random calls as stated in the comments. An example:

    #include <random>
    class Randomizer
    {
    public:
        Randomizer() : m_rand(0), counter(0), randomizer(0, std::numeric_limits<unsigned long long>::max()) {}
    
        bool RandomBool()
        {
            if (!counter)
            {
                m_rand = randomizer(std::mt19937(rd()));
                counter = sizeof(unsigned long long) * 8;
    
            }
            return (m_rand >> --counter) & 1;
        }
    private:
        std::random_device  rd;
        std::uniform_int_distribution<unsigned long long> randomizer;
        unsigned long long m_rand;
        int counter;
    };
    
    0 讨论(0)
  • 2020-12-23 22:16

    Apparently I have to add another answer. Just figured out that starting with Ivy Bridge architecture Intel added RdRand CPU instruction and AMD added it later in June 2015. So if you are targeting a processor that is new enough and don't mind using (inline) assembly, the fastest way to generate random bools should be in calling RdRand CPU instruction to get a 64-bit random number as described here (scroll to approximately the middle of the page for code examples) (at that link there is also a code example for checking the current CPU for support of RdRand instruction, and see also the Wikipedia for an explanation of how to do this with CPUID instruction), and then use the bits of that number for booleans as described in my Xorshit+ based answer.

    0 讨论(0)
提交回复
热议问题