Home

Awesome

Random for modern C++ with convenient API

Github-sponsors Build status Coverage Status<a href="https://scan.coverity.com/projects/effolkronium-random"><img alt="Coverity Scan Build Status" src="https://scan.coverity.com/projects/13062/badge.svg"/></a> Github-sponsors

Design goals

There are few ways to get working with random in C++:

  srand( time(NULL) ); // seed with time since epoch
  auto random_number = (rand() % 9) + 1; // get a pseudo-random integer between 1 and 9
  std::random_device random_device; // create object for seeding
  std::mt19937 engine{random_device()}; // create engine and seed it
  std::uniform_int_distribution<> dist(1,9); // create distribution for integers with [1; 9] range
  auto random_number = dist(engine); // finally get a pseudo-random integer number
  // auto seeded
  auto random_number = Random::get(1, 9); // invoke 'get' method to generate a pseudo-random integer in [1; 9] range
  // yep, that's all.

Supported compilers

Integration

CMake

add_subdirectory(random) # path to the 'random' library root
... # create target
target_link_libraries(${TARGET} effolkronium_random) # add include path to a compiler

First of all, build or|and install this project:

cd "path_to_root_of_the_library"
mkdir build
cd build
cmake -G"Visual Studio 15 2017" ..
cmake --build . --target install --config Release
ctest -C Release

Then, find the package by a cmake

find_package(effolkronium_random REQUIRED)
... # create target
target_link_libraries(${TARGET} effolkronium_random)

Manually

The single required source, file random.hpp is in the include/effolkronium directory.

Then

All you need to do is add

#include "effolkronium/random.hpp"

// get base random alias which is auto seeded and has static API and internal state
using Random = effolkronium::random_static;

to the files you want to use effolkronium random class. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., -std=c++11 for GCC and Clang).

Five-minute tutorial

Number range

Returns a pseudo-random number in a [first; second] range.

auto val = Random::get(-1, 1) // decltype(val) is int
// specify explicit type
auto val = Random::get<uint8_t>(-1, 1) // decltype(val) is uint8_t
// you able to use range from greater to lower
auto val = Random::get(1.l, -1.l) // decltype(val) is long double
auto val = Random::get(1.f, -1) // Error: implicit conversions are not allowed here.

Common type number range

Choose common type of two range arguments by std::common_type.

auto val = Random::get<Random::common>(1, 0.f) // decltype(val) is float
auto val = Random::get<Random::common>(0ul, 1ull) // decltype(val) is unsigned long long
auto val = Random::get<Random::common>(1.2l, 1.5f) // decltype(val) is long double
auto val = Random::get<Random::common>(1u, -1) // Error: prevent conversion from signed to unsigned.

Character range

Returns a pseudo-random character in a [first; second] range.

auto val = Random::get('a', 'z')
auto val = Random::get(L'㋐', L'㋾')
auto val = Random::get<wchar_t>()

Bool

Generate true with [0; 1] probability

auto val = Random::get<bool>(0.7) // true with 70% probability
auto val = Random::get<bool>() // true with 50% probability by default
auto val = Random::get<bool>(-1) // Error: assert occurred! Out of [0; 1] range

Random value from std::initializer_list

Return random value from values in a std::initializer_list

auto val = Random::get({1, 2, 3}) // val = 1 or 2 or 3

Random iterator

Return random iterator from iterator range or container. Iterator must be at least Input iterator. If a std::distance(first, last) == 0, return the 'last' iterator. If container is empty, return std::end(container) iterator.

std::array<int, 3> array{ {1, 2, 3} };
auto randomIt = Random::get( array.begin(), array.end() );
auto randomIt = Random::get( array );

Random element from array

Return pointer to random element in built-in array

int array [] = {1, 2, 3};
auto randomPtr = Random::get( array );

Container of random values

Return container filled with random numbers. Any containers with "begin", "end" and "insert" methods are applicable

auto vec = Random::get<std::vector>(1, 9, 5); // decltype(vec) is std::vector<int> with size = 5
// Note: "reserve" method invokes automatically for performance

auto mset = Random::get<std::multiset>(1.0, 9.9, 10); // decltype(mset) is std::multiset<double> with size = 10

auto arr = Random::get<std::array, 5>('0', '9'); // decltype(arr) is std::array<char, 5>
// Warning: Returning arrays with large size could be ineficcient

auto vec = Random::get<std::vector>(1l, 9ll, 5); // decltype(vec) is std::vector<long long> with size = 5

template<typename T>
class MyContainer
{
    iterator begin() {...}
    iterator end() {...}
    void insert(iterator after, T value) {...}
};

auto vec = Random::get<MyContainer>(1, 9, 5); // decltype(vec) is std::MyContainer<int> with size = 5

Weighted random values

Return random iterator from map-like containers

    std::unordered_map<std::string, unsigned long> nonzero_ulong_umap = {{"Orange", 1ul}, {"Apple", 2ul}, {"Banana", 3ul}};
    std::unordered_map<std::string, unsigned> nonzero_uint_umap = {{"Orange", 1u}, {"Apple", 2u}, {"Banana", 3u}};
    
    std::map<std::string, float> nonzero_float_map = {{"Orange", 1.0f}, {"Apple", 2.0f}, {"Banana", 3.0f}};
    std::map<std::string, double> nonzero_double_map = {{"Orange", 1.0}, {"Apple", 2.0}, {"Banana", 3.0}};

    Random::get<Random_t::weight>(nonzero_ulong_umap);
    Random::get<Random_t::weight>(nonzero_uint_umap);
    Random::get<Random_t::weight>(nonzero_float_map);
    Random::get<Random_t::weight>(nonzero_double_map);

Shuffle

Reorders the elements in a given range or in all container ref

std::array<int, 3> array{ {1, 2, 3} };
Random::shuffle( array.begin( ), array.end( ) )
Random::shuffle( array )

Custom distribution

Return result from operator() of a distribution with internal random engine argument

// 1.f and 2.f will be forwarded to std::gamma_distribution constructor
auto result = Random::get<std::gamma_distribution<>>( 1.f, 2.f );
std::gamma_distribution<> gamma{ 1.f, 2.f };
auto result = Random::get( gamma ); // return result of gamma.operator()( engine_ )

Custom Seeder

Specify seed by which random engine will be seeded at construction time:

struct MySeeder {
    unsigned operator() () {
        return 42u;
    }
};
    
// Seeded by 42
using Random = effolkronium::basic_random_static<std::mt19937, MySeeder>;

Because we can't copy std::seed_seq, the 'random' library destroy seeder instance after engine seeding. So it's safe to return seed by reference.

struct MySeeder {
    // std::seed_seq isn't copyable
    std::seed_seq& operator() () {
        return seed_seq_;
    }
    std::seed_seq seed_seq_{ { 1, 2, 3, 4, 5 } };
};
    
// Seeded by seed_seq_ from MySeeder
using Random = effolkronium::basic_random_static<std::mt19937, MySeeder>;

Seed an internal random engine by a newly created Seeder instance

Random::reseed( );

Thread local random

It uses static methods API and data with thread_local storage which is fully thread safe (but less performance)

using Random = effolkronium::random_thread_local

// use in the same way as random_static. Thread safe
std::thread first{ [ ] { Random::get( ); } };
std::thread second{ [ ] { Random::get( ); } };

Local random

It uses non static methods API and data with auto storage which can be created on the stack at local scope

#include "effolkronium/random.hpp"

using Random_t = effolkronium::random_local

int main( ) {
  Random_t localRandom{ }; // Construct on the stack
  
  // access throughout dot
  auto val = localRandom.get(-10, 10);
  
} // Destroy localRandom and free stack memory

Seeding

ref

Set new seed for an internal random engine.

Random::seed( 10 ); // 10 is new seed number

std::seed_seq sseq{ 1, 2, 3 };
Random::seed( sseq ); // use seed sequence here

Min value

ref

Returns the minimum value potentially generated by the internal random-number engine

auto minVal = Random::min( );

Max value

ref

Returns the maximum value potentially generated by the internal random-number engine

auto maxVal = Random::max( );

get without arguments

ref

Returns the random number in [ Random::min( ), Random::max ] range

auto val = Random::get( );
// val is random number in [ Random::min( ), Random::max ] range

engine

Returns reference to the internal engine.

auto& engine = Random::engine( );
std::sample(itBeg, itEnd, std::back_inserter(out), 5, Random::engine( ));

Get engine

Returns copy of internal engine.

auto engine = Random::get_engine( );

Discard

ref

Advances the internal engine's state by a specified amount. Equivalent to calling Random::get() N times and discarding the result.

Random::discard( 500 );

IsEqual

ref

Compares internal pseudo-random number engine with other pseudo-random number engine.

Random::Engine otherEngine;
bool isSame = Random::is_equal( otherEngine );

Serialize

ref

Serializes the internal state of the internal pseudo-random number engine as a sequence of decimal numbers separated by one or more spaces, and inserts it to the output stream. The fill character and the formatting flags of the stream are ignored and unaffected.

std::stringstream strStream;
Random::serialize( strStream ); // the strStream now contain internal state of the Random internal engine

Deserialize

ref

Restores the internal state of the internal pseudo-random number engine from the serialized representation, which was created by an earlier call to 'serialize' using a stream with the same imbued locale and the same CharT and Traits. If the input cannot be deserialized, internal engine is left unchanged and failbit is raised on input stream.

std::stringstream strStream;
Random::serialize( strStream );

// ...

Random::deserialize( strStream ); // Restore internal state of internal Random engine