The basics of <random>
Erich Keane
Software Engineer, iCDG, Intel
Erich.Keane@verizon.net
rand() is wrong AND You're using it wrong!
- Seeding
- void srand(unsigned seed);
- 32-bit seed value, very limited seed values
- Only ~4.3 Billion states!-- Trivially calculable
- Strangles better rand() implementations
- srand(time(NULL));
- 'time' only has a 1 Hz frequency!
- VERY predictable
- ENTIRE 32 bit space is only ~136 years
- I KNOW your app seeded in the last:
- Decade : ~315,360,000: 29 bits/entropy
- Year: ~31,536,000: 25 bits/entropy
- Month: ~2,592,000: ~22 bits/entropy
rand() is wrong AND You're using it wrong!
- Entropy
- rand() returns int from 0->RAND_MAX
- Many platforms: RAND_MAX == 32767
- Many others scale to get that far!
- History of short-comings, still many biased to even/odds
- Most are Linear congruential engine
- VERY Low quality random
- COMPLETELY and predictably Deterministic!
- rand() returns int from 0->RAND_MAX
rand() is wrong AND You're using it wrong!
- Distribution
- rand() % 1000
- Biased for # < RAND_MAX % 1000
- [0, 999] -> [0, 999]
- [1000, 1999] -> [0, 999]
- [32000, 32767] -> [0, 767] <-- MORE likely!
- Floating-point has similar issues
- Some values still more likely (see above!)
- Some values not possible based on FP precision/mappings
- rand() % 1000
Enter C++11: <random>
- Reasonably easy to use
- Provides a 'best try' at Non-deterministic behavior
- std::random_device
- Provides random-number engines
- std::linear_congruential_engine
- std::mersenne_twister_engine
- std::subtract_with_carry_engine
- Provides MANY Distributions!
- Uniform
- Bernoulli
- Poisson
- Normal
- Sampling Distributions
- TOGETHER, these combine for REALLY GOOD random
std::random_device
- Non-deterministic (if possible)
- Otherwise degrades to best-possible
- g++: rd_rand instruction
- clang: /dev/urandom
- EASY to use!
- Note: do NOT use %!
std::random_device rd; // Instantiates a RNG!
unsigned int rand_num = rd(); // generates a random number!Engines
- Completely customizable
- Provides typedefs for commonly used configurations
- std::linear_congruential_engine
- minstd_rand0, minstd_rand
- std::mersenne_twister_engine
- mt19937, mt19937_64
- std::linear_congruential_engine
- Can be seeded with FULL entropy (std::seed_seq)
- Gotcha: "Correctly" seeding difficult, see PCG or boost::random!
std::random_device rd; // Instantiates a RNG!
std::array <unsigned int, 624> entropy; // 624 is magic number for MT :(
std::generate(std::begin(entropy), std::end(entropy), std::ref(rd));
std::seed_seq seq{entropy}; // Seed Sequence Ready
std::mt19937 engine{seq}; // Create engine for MT random numbers
unsigned int rnd_val = engine(); // rnd_val is a random number!Distributions
- Works correctly! Guarantees correct distribution
- Uniform, Bernoulli, Poisson, Normal, Sample distributions available
std::random_device rd; // Instantiates a RNG!
std::array <unsigned int, 624> entropy; // 624 is magic number for MT :(
std::generate(std::begin(entropy), std::end(entropy), std::ref(rd));
std::seed_seq seq{entropy}; // Seed Sequence Ready
std::mt19937 engine{seq}; // Create engine for MT random numbers
std::uniform_int_distribution<int> int_dist{1,5};
int rand_int = int_dist(engine); // rand_int is [1,5]
std::uniform_real_distribution<double> double_dist{1, 1.5};
double rand_double = double_dist(engine); // [1, 1.5)Still Some Problems:
- Not Crypto-secure, except for deterministic random_device
- Correctly seeding is REALLY hard (see examples in this presentation)
- http://www.pcg-random.org/posts/cpp-seeding-surprises.html
- Can use PCG, or Boost, both which make it easier
- Alternatively, creating a seed_seq with a random device is pretty easy (See next slide!)
Still Some Problems:
Fixing the Seed Problem:
// Note: Not actually SeedSequence,
// lacks default/init-list ctors and params method
template <class RandType>
class GenSeq
{
public:
using result_type = typename RandType::result_type;
GenSeq(RandType& rt):_rt(rt){}
size_t size() const{ return std::numeric_limits<size_t>::max();}
template< class RandomIt>
void generate( RandomIt begin, RandomIt end)
{
std::generate(begin, end, std::ref(_rt));
}
private:
RandType& _rt;
};
int main()
{
std::random_device rd;
GenSeq<std::random_device> seq { rd };
std::mt19937 engine { seq };
std::cout << engine() << '\n';
}Q&A
Erich.Keane@verizon.net
Template-Templates
Erich Keane
Software Engineer, iCDG, Intel
Erich.Keane@verizon.net
What ARE Template-Templates?
- Component of Template-Meta-Programming (TMP)
- Allow matching of template-parameters of template-parameters!
- Particularly useful with Variadic-Templates, less interesting otherwise thanks to type-traits
Simple Examples
- Matching/using the internal types of a collection
- A bit contrived, since ::value_type exists
template<template<typename, typename> class T, typename IT, typename Alloc>
void DoThingToVector(T<IT, Alloc> vect)
{
std::cout << typeid(IT).name() <<std::endl;
}
int main()
{
std::vector<int> iv;
std::vector<double> dv;
std::vector<std::string> sv;
DoThingToVector(iv);
DoThingToVector(dv);
DoThingToVector(sv);
}
// Results:
i
d
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Simple Examples
- Specialization based on sub-type!
template<template<typename, typename> class T, typename IT, typename Alloc>
void DoThingToVector(T<IT, Alloc> vect)
{
std::cout << typeid(IT).name() <<std::endl;
}
template<template<typename, typename> class T, typename Alloc>
void DoThingToVector(T<std::string, Alloc> vect)
{
std::cout << "std::string!" <<std::endl;
}
int main()
{
std::vector<int> iv;
std::vector<double> dv;
std::vector<std::string> sv;
DoThingToVector(iv);
DoThingToVector(dv);
DoThingToVector(sv);
}
// Results:
i
d
std::string!
Variadic Examples
- Match internal types of a Variadic-container
template<template<typename...> class T, typename FST, typename SCD, typename...Rest>
void PrintSecondType(T<FST,SCD,Rest...>)
{
std::cout << typeid(SCD).name() << std::endl;
}
int main()
{
std::tuple<int, double, std::string> tp1;
std::tuple<int, float, std::string> tp2;
std::tuple<int, char, std::string> tp3;
PrintSecondType(tp1);
PrintSecondType(tp2);
PrintSecondType(tp3);
}
// Results:
d
f
c
Variadic Examples
- Match Params to Function-Pointer-Wrapper
template<typename Func>
struct func_get;
template<template <typename...> class Func, typename... Args, typename Ret>
struct func_get<Func<Ret(Args...)>>
{
template<size_t Index>
using argument_type = typename std::tuple_element<Index, std::tuple<Args...> >::type;
};
int main()
{
std::function<int(double, float, char, int)> f;
static_assert(is_same<double,func_get<decltype(f)>::argument_type<0>>::value, "Failed!");
static_assert(is_same<float,func_get<decltype(f)>::argument_type<1>>::value, "Failed!");
static_assert(is_same<char,func_get<decltype(f)>::argument_type<2>>::value, "Failed!");
static_assert(is_same<int,func_get<decltype(f)>::argument_type<3>>::value, "Failed!");
}
Q&A
Erich.Keane@verizon.net
Random And Template-Templates
By Erich Keane
Random And Template-Templates
PDXCPP Slides covering the C++11 Random functionality as well as Template-Templates.
- 852