Advertisement
Guest User

my_random.hpp

a guest
Apr 6th, 2020
256
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.65 KB | None | 0 0
  1. #pragma once
  2. // Based on
  3. // <url: https://github.com/alf-p-steinbach/cppx-core/blob/master/source/cppx-core/
  4. // stdlib-wrappers/random-numbers-util.hpp>
  5.  
  6. #include <limits.h>         // CHAR_BIT
  7.  
  8. #include <type_traits>      // std::(conditional_t, is_same_v, is_unsigned_v)
  9. #include <utility>          // std::exchange
  10.    
  11. #ifdef __GNUC__
  12. #   ifndef NO_WARNING_ABOUT_RANDOM_DEVICE_PLEASE
  13. #       ifndef  _GLIBCXX_USE_RANDOM_TR1
  14. #           pragma GCC warning \
  15. "_GLIBCXX_USE_RANDOM_TR1 is not defined: `std::random_device` may use a fixed sequence."
  16. #       endif
  17. #   endif
  18. #endif
  19. #include <random>           // std::*
  20.  
  21. namespace util::std_random {
  22.     namespace _alias { namespace std_random = util::std_random; }
  23.  
  24.     using
  25.         std::conditional_t, std::is_same_v, std::is_unsigned_v,
  26.         std::exchange,
  27.         std::mt19937_64, std::mt19937, std::random_device,
  28.         std::uniform_int_distribution,
  29.         std::uniform_real_distribution;
  30.  
  31.     constexpr int   bits_per_byte               = CHAR_BIT;
  32.     template< class T > constexpr int bits_per_ = bits_per_byte*sizeof( T );
  33.    
  34.     constexpr bool  system_is_64_bit_or_more    = (bits_per_<void*> >= 64);
  35.  
  36.     // A more well-defined, more reliable alternative to std::default_random_engine.
  37.     using Generator     = conditional_t< system_is_64_bit_or_more,
  38.         std::mt19937_64,            // Efficient for 64-bit systems.
  39.         std::mt19937                // Efficient for 32-bit systems.
  40.         >;
  41.     using Bits_value    = Generator::result_type;
  42.  
  43.     static_assert( is_unsigned_v<Bits_value> );
  44.     static_assert( sizeof( Bits_value ) >= sizeof( unsigned ) );
  45.     static_assert( is_same_v<random_device::result_type, unsigned> );
  46.  
  47.     inline auto hardware_entropy()
  48.         -> unsigned
  49.     {
  50.         static random_device the_entropy_source;
  51.         return the_entropy_source();
  52.     }
  53.  
  54.     class Seed
  55.     {
  56.         Bits_value  m_value;
  57.  
  58.     public:
  59.         auto value() const noexcept -> Bits_value { return m_value; }
  60.  
  61.         Seed()  noexcept: m_value( 0 ) {}
  62.         explicit Seed( const Bits_value value = 0 )  noexcept: m_value( value ) {}
  63.     };
  64.  
  65.     static inline auto random_seed()
  66.         -> Seed
  67.     {
  68.         constexpr auto div_up = []( size_t a, size_t b ) { return (a + b - 1)/b; };
  69.  
  70.         // Not using std::independent_bits_engine because it copies the underlying engine.
  71.         Bits_value value = 0;
  72.         constexpr int n_chunks = int( div_up( sizeof( Bits_value ), sizeof( unsigned ) ) );
  73.         static_assert( n_chunks >= 1 );
  74.         for( int i = 1; true; ++i ) {
  75.             value |= hardware_entropy();
  76.             if( i == n_chunks ) {
  77.                 break;
  78.             }
  79.             value <<= bits_per_<unsigned>;
  80.         }
  81.         return Seed( value );
  82.     }
  83.  
  84.     class Bits:
  85.         public Generator
  86.     {
  87.     public:
  88.         using Generator::Generator;
  89.  
  90.         explicit Bits( const Seed seed = random_seed() ):
  91.             Generator( seed.value() )
  92.         {}
  93.  
  94.         auto next()
  95.             -> Bits_value
  96.         { return operator()(); }
  97.     };
  98.  
  99.     class Choices
  100.     {
  101.         Bits            m_bits_generator;
  102.         Bits_value      m_value;
  103.         int             m_n_bits_consumed;
  104.    
  105.     public:
  106.         explicit Choices( const Seed seed = random_seed() ):
  107.             m_bits_generator( seed ),
  108.             m_value( 0 ),
  109.             m_n_bits_consumed( bits_per_<Bits_value> )
  110.         {}
  111.  
  112.         auto generator()
  113.             -> Generator&
  114.         { return m_bits_generator; }
  115.  
  116.         auto next()
  117.             -> bool
  118.         {
  119.             if( m_n_bits_consumed == bits_per_<Bits_value> ) {
  120.                 m_value = m_bits_generator.next();
  121.                 m_n_bits_consumed = 0;
  122.             }
  123.             ++m_n_bits_consumed;
  124.             return !!(exchange( m_value, m_value/2 ) % 2);
  125.         }
  126.     };
  127.  
  128.     template< class Integer >
  129.     class Integers_
  130.     {
  131.         using Adapter = uniform_int_distribution<Integer>;
  132.  
  133.         Bits            m_bits_generator;
  134.         Adapter         m_adapt;
  135.  
  136.     public:
  137.         explicit Integers_( const Integer n_unique_values, const Seed seed = random_seed() ):
  138.             m_bits_generator( seed ),
  139.             m_adapt( 0, n_unique_values - 1 )
  140.         {}
  141.  
  142.         auto generator()
  143.             -> Generator&
  144.         { return m_bits_generator; }
  145.  
  146.         auto next()
  147.             -> Integer
  148.         { return m_adapt( m_bits_generator ); }
  149.     };
  150.  
  151.     template< class Integer = int >
  152.     struct Integer_
  153.     {
  154.         static auto from( Generator& g, const Integer n_unique_values )
  155.             -> Integer
  156.         { return uniform_int_distribution<Integer>( 0, n_unique_values - 1 )( g ); }
  157.     };
  158.  
  159.     template< class Number >        // For floating point numbers, e.g. `double`.
  160.     class Numbers_
  161.     {
  162.         using Adapter = std::uniform_real_distribution<Number>;
  163.  
  164.         Bits            m_bits_generator;
  165.         Adapter         m_adapt;
  166.  
  167.     public:
  168.         explicit Numbers_( const Seed seed = random_seed() ):
  169.             m_bits_generator( seed )
  170.         {}
  171.  
  172.         auto generator()
  173.             -> Generator&
  174.         { return m_bits_generator; }
  175.  
  176.         auto next()
  177.             -> Number
  178.         { return m_adapt( m_bits_generator ); }
  179.     };
  180.  
  181.     template< class Number >
  182.     struct Number_
  183.     {
  184.         static auto from( Generator& g )
  185.             -> Number
  186.         { return std::uniform_real_distribution<Number>()( g ); }
  187.     };
  188.  
  189.     using Integers  = Integers_<int>;
  190.     using Integer   = Integer_<int>;
  191.     using Numbers   = Numbers_<double>;
  192.     using Number    = Number_<double>;
  193.  
  194. }  // namespace util::std_random
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement