summaryrefslogtreecommitdiffstats
path: root/src/FastRandom.h
diff options
context:
space:
mode:
authorpeterbell10 <peterbell10@live.co.uk>2017-06-13 21:35:30 +0200
committerLukas Pioch <lukas@zgow.de>2017-06-13 21:35:30 +0200
commit360d8eade0332f2c1aa5c205ca772cd506c35b26 (patch)
tree066fde557310742a39020bad9bc4aa2a5ef8d51a /src/FastRandom.h
parentCorrected check for level of subcommand and fixed multiple levels not working (#3758) (diff)
downloadcuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar.gz
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar.bz2
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar.lz
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar.xz
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.tar.zst
cuberite-360d8eade0332f2c1aa5c205ca772cd506c35b26.zip
Diffstat (limited to 'src/FastRandom.h')
-rw-r--r--src/FastRandom.h200
1 files changed, 165 insertions, 35 deletions
diff --git a/src/FastRandom.h b/src/FastRandom.h
index a21da8391..77bafc217 100644
--- a/src/FastRandom.h
+++ b/src/FastRandom.h
@@ -4,17 +4,10 @@
// Declares the cFastRandom class representing a fast random number generator
/*
-The cFastRandom aims to provide a very fast, although not very cryptographically secure, random generator.
-It is fast to instantiate, fast to query next, and partially multi-thread-safe.
-It is multi-thread-safe in the sense that it can be accessed from multiple threads without crashing, but it may
-yield duplicate numbers in that case.
-
-Internally, this works similar to cNoise's integral noise generation, with some predefined inputs: the seed is
-taken from a global counter and the random is calculated using a counter that is incremented on each use (hence
-the multi-thread duplication). Two alternatives exists for each function, one that takes a range parameter,
-and another that takes an additional "salt" parameter; this salt is used as an additional input to the random,
-in order to avoid multi-thread duplication. If two threads both use the class at the same time with different
-salts, the values they get will be different.
+The cFastRandom alias should be avoided in favor of the result of a call to GetRandomProvider().
+The MTRand generator used is faster, has a better range and provides higher quality randomness.
+Note that MTRand is relatively costly to construct and so instances should be long lived,
+prefer calls to GetRandomProvider over creating new instances.
*/
@@ -23,58 +16,195 @@ salts, the values they get will be different.
#pragma once
#include <random>
+#include <type_traits>
+#include <limits>
-class cFastRandom
+namespace Detail
+{
+ /** Returns a low quality seed. */
+ UInt32 GetRandomSeed();
+
+ /** Aliases true_type if Char is any variant of char ignoring signed-ness. */
+ template <class Char>
+ using IsChar = typename std::is_same<typename std::make_signed<Char>::type, signed char>::type;
+
+ template <class IntType>
+ struct cUniformImpl :
+ public std::conditional<
+ IsChar<IntType>::value,
+ typename std::conditional< // Match signed-ness of IntType
+ std::is_signed<IntType>::value,
+ std::uniform_int_distribution<short>,
+ std::uniform_int_distribution<unsigned short>
+ >::type,
+ std::uniform_int_distribution<IntType>
+ >
+ {
+ };
+
+ /** uniform_int_distribution<char> is undefined so this aliases a valid type. */
+ template <class IntType>
+ using cUniform = typename cUniformImpl<IntType>::type;
+}
+
+
+
+
+
+/** Class to wrap any random engine to provide a more convenient interface. */
+template <class RandomEngine>
+class cRandomWrapper
{
public:
+ /** Initialize with a low quality seed. */
+ cRandomWrapper():
+ m_Engine(Detail::GetRandomSeed())
+ {
+ }
- cFastRandom(void);
- /** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */
- int NextInt(int a_Range);
+ /** Initialize with a SeedSequence. */
+ template <class SeedSeq>
+ cRandomWrapper(SeedSeq & a_SeedSeq):
+ m_Engine(a_SeedSeq)
+ {
+ }
- /** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */
- float NextFloat(float a_Range);
- /** Returns a random float between 0 and 1. */
- float NextFloat(void) { return NextFloat(1); }
- /** Returns a random int in the range [a_Begin .. a_End] */
- int GenerateRandomInteger(int a_Begin, int a_End);
+ /** Return a random IntType in the range [a_Min, a_Max]. */
+ template <class IntType = int, class ArgType>
+ IntType RandInt(ArgType a_Min, ArgType a_Max)
+ {
+ ASSERT(
+ (a_Max >= a_Min) &&
+ (a_Max <= std::numeric_limits<IntType>::max()) &&
+ (a_Min >= std::numeric_limits<IntType>::min())
+ );
+ Detail::cUniform<IntType> dist(
+ static_cast<IntType>(a_Min),
+ static_cast<IntType>(a_Max)
+ );
+ return static_cast<IntType>(dist(m_Engine));
+ }
-private:
- std::minstd_rand m_LinearRand;
-};
+ /** Return a random IntType in the range [0, a_Max]. */
+ template <class IntType = int, class ArgType>
+ IntType RandInt(ArgType a_Max)
+ {
+ ASSERT((a_Max >= 0) && (a_Max <= std::numeric_limits<IntType>::max()));
+ Detail::cUniform<IntType> dist(IntType(0), static_cast<IntType>(a_Max));
+ return static_cast<IntType>(dist(m_Engine));
+ }
+
+
+
+
+
+ /** Return a random IntType in the range [0, std::numeric_limits<IntType>::max()]. */
+ template <class IntType = int>
+ IntType RandInt()
+ {
+ Detail::cUniform<IntType> dist(IntType(0), std::numeric_limits<IntType>::max());
+ return static_cast<IntType>(dist(m_Engine));
+ }
+
+
+
+
+
+ /** Return a random RealType in the range [a_Min, a_Max). */
+ template <class RealType = float, class ArgType>
+ RealType RandReal(ArgType a_Min, ArgType a_Max)
+ {
+ std::uniform_real_distribution<RealType> dist(a_Min, a_Max);
+ return dist(m_Engine);
+ }
-class MTRand
-{
-public:
- MTRand(void);
- /** Returns a random integer in the range [0 .. a_Range]. */
- int randInt(int a_Range);
- /** Returns a random integer in the range [0 .. MAX_INT]. */
- int randInt(void);
+ /** Return a random RealType in the range [0, a_Max). */
+ template <class RealType = float, class ArgType>
+ RealType RandReal(ArgType a_Max)
+ {
+ std::uniform_real_distribution<RealType> dist(RealType(0), a_Max);
+ return dist(m_Engine);
+ }
- /** Returns a random floating point number in the range [0 .. a_Range]. */
- double rand(double a_Range);
+
+
+
+
+ /** Return a random RealType in the range [0, 1). */
+ template <class RealType = float>
+ RealType RandReal()
+ {
+ std::uniform_real_distribution<RealType> dist;
+ return dist(m_Engine);
+ }
+
+
+
+
+
+ /** Return a random bool with the given probability of being true. */
+ bool RandBool(double a_TrueProbability = 0.5)
+ {
+ std::bernoulli_distribution dist(a_TrueProbability);
+ return dist(m_Engine);
+ }
+
+
+
+
+ /** Returns a reference to the underlying random engine. */
+ RandomEngine & Engine()
+ {
+ return m_Engine;
+ }
private:
- std::mt19937 m_MersenneRand;
+ RandomEngine m_Engine;
};
+
+/** Utility to seed a random engine with maximal entropy from random_device. */
+struct cRandomDeviceSeeder
+{
+ using result_type = std::random_device::result_type;
+
+ template <class Itr>
+ void generate(Itr first, Itr last)
+ {
+ std::random_device rd;
+ std::uniform_int_distribution<result_type> dist;
+ for (; first != last; ++first)
+ {
+ *first = dist(rd);
+ }
+ }
+};
+
+
+
+
+
+using cFastRandom = cRandomWrapper<std::minstd_rand>;
+using MTRand = cRandomWrapper<std::mt19937>;
+
+/** Returns the current thread's random number source. */
+MTRand & GetRandomProvider();