IsaacRandom.h
// IsaacRandom.h
#pragma once
#ifndef Ceda_cxUtils_IsaacRandom_H
#define Ceda_cxUtils_IsaacRandom_H
/*
ISAAC: a fast cryptographic random number generator
ISAAC (Indirection, Shift, Accumulate, Add, and Count) generates 32-bit random numbers. Averaged
out, it requires 18.75 machine cycles to generate each 32-bit value. Cycles are guaranteed to be
at least 2^40 values long, and they are 2^8295 values long on average. The results are uniformly
distributed, unbiased, and unpredictable unless you know the seed.
*/
#include "BasicTypeSizes.h"
#include "cxUtils.h"
#include <mutex>
#include <type_traits>
#include <limits>
namespace ceda
{
// Recommended: 8 for crypto, 4 for simulations
const int RANDSIZL = 8;
// Context of random number generator
struct randctx
{
uint32 randcnt;
uint32 randrsl[1 << RANDSIZL];
uint32 randmem[1 << RANDSIZL];
uint32 randa;
uint32 randb;
uint32 randc;
};
struct cxUtils_API IsaacSeed
{
IsaacSeed() : seed1(0), seed2(0), seed3(0), seed4(0) {}
int32 seed1;
int32 seed2;
int32 seed3;
int32 seed4;
void SeedFromClock();
};
class cxUtils_API IsaacRandomNumberGen
{
public:
explicit IsaacRandomNumberGen(bool seedFromClock = false);
IsaacRandomNumberGen(int32 seed1, int32 seed2, int32 seed3, int32 seed4);
IsaacRandomNumberGen(const IsaacSeed& seed);
void SeedFromClock();
void Init(int32 seed1=0, int32 seed2=0, int32 seed3=0, int32 seed4=0);
void Init(const IsaacSeed& seed);
// Measured generation rate: 20 million per sec on 2GHz Pentium IV
int32 operator()();
// Generate random number in range [x1,x2). Interval must be non-empty.
// Measured generation rate: 11 million per sec on 2GHz Pentium IV
int32 GetUniformDistInteger(int32 x1,int32 x2);
int64 GetUniformDistInteger(int64 x1,int64 x2);
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T GetUniformDistInteger(T x1, T x2)
{
if constexpr (std::numeric_limits<T>::digits <= 32)
{
return static_cast<T>(GetUniformDistInteger(static_cast<int32>(x1),static_cast<int32>(x2)));
}
else
{
return static_cast<T>(GetUniformDistInteger(static_cast<int64>(x1),static_cast<int64>(x2)));
}
}
ssize_t GetUniformDistInteger_ssize_t(ssize_t x1, ssize_t x2)
{
return GetUniformDistInteger(x1,x2);
}
//double GetUniformDistDouble(double x1,double x2);
// Use this random number generator to create a random seed value.
void SetRandomSeed(IsaacSeed& seed);
private:
randctx ctx;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// ThreadSafeRandomNumberGen
class ThreadSafeRandomNumberGen
{
public:
int32 GetUniformDistInteger(int32 x1,int32 x2)
{
std::lock_guard<std::mutex> lock(mutex_);
return isaac_.GetUniformDistInteger(x1,x2);
}
int64 GetUniformDistInteger(int64 x1,int64 x2)
{
std::lock_guard<std::mutex> lock(mutex_);
return isaac_.GetUniformDistInteger(x1,x2);
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T GetUniformDistInteger(T x1, T x2)
{
if constexpr (std::numeric_limits<T>::digits <= 32)
{
return static_cast<T>(GetUniformDistInteger(static_cast<int32>(x1),static_cast<int32>(x2)));
}
else
{
return static_cast<T>(GetUniformDistInteger(static_cast<int64>(x1),static_cast<int64>(x2)));
}
}
ssize_t GetUniformDistInteger_ssize_t(ssize_t x1, ssize_t x2)
{
return GetUniformDistInteger(x1,x2);
}
private:
IsaacRandomNumberGen isaac_;
mutable std::mutex mutex_;
};
} // namespace ceda
#endif // include guard