From 1cc7699939b0f527e2fe4382bd31f084005ba8d3 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 18 Nov 2021 20:19:29 +0100 Subject: [PATCH] Moved rng-methods to their own class/header --- Eule/Eule.vcxproj | 2 + Eule/Eule.vcxproj.filters | 6 ++ Eule/Math.cpp | 77 +------------------ Eule/Math.h | 27 ------- Eule/Random.cpp | 73 ++++++++++++++++++ Eule/Random.h | 41 ++++++++++ Test/Math__Oscillate.cpp | 49 ++++++------ Test/Random.cpp | 1 + Test/Random.h | 41 ++++++++++ ...IntRange.cpp => Random_RandomIntRange.cpp} | 14 ++-- ...ath_Random.cpp => Random__RandomFloat.cpp} | 8 +- ...mInteger.cpp => Random__RandomInteger.cpp} | 8 +- ...andomRange.cpp => Random__RandomRange.cpp} | 12 +-- Test/_Test_Eule.vcxproj | 8 +- Test/_Test_Eule.vcxproj.filters | 27 ++++--- 15 files changed, 233 insertions(+), 161 deletions(-) create mode 100644 Eule/Random.cpp create mode 100644 Eule/Random.h create mode 100644 Test/Random.cpp create mode 100644 Test/Random.h rename Test/{Math_RandomIntRange.cpp => Random_RandomIntRange.cpp} (85%) rename Test/{Math_Random.cpp => Random__RandomFloat.cpp} (74%) rename Test/{Math_RandomInteger.cpp => Random__RandomInteger.cpp} (88%) rename Test/{Math__RandomRange.cpp => Random__RandomRange.cpp} (85%) diff --git a/Eule/Eule.vcxproj b/Eule/Eule.vcxproj index 269a6be..ae09deb 100644 --- a/Eule/Eule.vcxproj +++ b/Eule/Eule.vcxproj @@ -23,6 +23,7 @@ + @@ -34,6 +35,7 @@ + diff --git a/Eule/Eule.vcxproj.filters b/Eule/Eule.vcxproj.filters index 3b2e0a2..545d178 100644 --- a/Eule/Eule.vcxproj.filters +++ b/Eule/Eule.vcxproj.filters @@ -39,6 +39,9 @@ Quelldateien + + Quelldateien + @@ -74,5 +77,8 @@ Headerdateien + + Headerdateien + \ No newline at end of file diff --git a/Eule/Math.cpp b/Eule/Math.cpp index 652ee8b..4c8a3c7 100644 --- a/Eule/Math.cpp +++ b/Eule/Math.cpp @@ -4,77 +4,6 @@ using namespace Eule; -// Checks if the random number generator is initialized. Does nothing if it is, initializes if it isn't. -#define MAKE_SURE_RNG_IS_INITIALIZED if (!isRngInitialized) InitRng(); - -void Math::InitRng() -{ - // Create truly random source (from hardware events) - std::random_device randomSource; - - // Generate enough truly random values to populate the entire state of the mersenne twister - std::array seedValues; - std::generate_n(seedValues.data(), seedValues.size(), std::ref(randomSource)); - std::seed_seq seedSequence(seedValues.begin(), seedValues.end()); - - // Seed the mersenne twister with these values - rng = std::mt19937(seedSequence); - - isRngInitialized = true; - - return; -} - -// Will return a random double between 0 and 1 -double Math::Random() -{ - MAKE_SURE_RNG_IS_INITIALIZED; - - return (rng() % 694206942069ll) / 694206942069.0; -} - -// Will return a random unsigned integer. -unsigned int Math::RandomUint() -{ - MAKE_SURE_RNG_IS_INITIALIZED; - - return rng(); -} - -// Will return a random integer -unsigned int Math::RandomInt() -{ - MAKE_SURE_RNG_IS_INITIALIZED; - - // Since this is supposed to return a random value anyways, - // we can let the random uint overflow without any problems. - return (int)rng(); -} - -// Will return a random double within a range -// These bounds are INCLUSIVE! -double Math::RandomRange(double min, double max) -{ - return (Random() * (max - min)) + min; -} - -// Will return a random integer within a range. This is faster than '(int)RandomRange(x,y)' -// These bounds are INCLUSIVE! -int Math::RandomIntRange(int min, int max) -{ - return (rng() % (max + 1 - min)) + min; -} - -double Math::Oscillate(const double a, const double b, const double counter, const double speed) -{ - return (sin(counter * speed * PI - HALF_PI) * 0.5 + 0.5) * (b-a) + a; -} - -bool Math::RandomChance(const double chance) -{ - return Random() <= chance; -} - int Math::Mod(const int numerator, const int denominator) { if (denominator == 0) @@ -94,5 +23,7 @@ int Math::Mod(const int numerator, const int denominator) return (denominator + (numerator % denominator)) % denominator; } -std::mt19937 Math::rng; -bool Math::isRngInitialized = true; +double Math::Oscillate(const double a, const double b, const double counter, const double speed) +{ + return (sin(counter * speed * PI - HALF_PI) * 0.5 + 0.5) * (b - a) + a; +} diff --git a/Eule/Math.h b/Eule/Math.h index 53fcef3..2be16c2 100644 --- a/Eule/Math.h +++ b/Eule/Math.h @@ -1,5 +1,4 @@ #pragma once -#include #include namespace Eule @@ -30,26 +29,6 @@ namespace Eule //! Will compute the actual modulo of a fraction. The % operator returns bs for n<0. //! May throw division-by-zero std::logic_error [[nodiscard]] static int Mod(const int numerator, const int denominator); - - //! Will return a random double between `0` and `1` - static double Random(); - - //! Will return a random unsigned integer. - static unsigned int RandomUint(); - - //! Will return a random integer - static unsigned int RandomInt(); - - //! Will return a random double within a range - //! These bounds are INCLUSIVE! - static double RandomRange(const double min, const double max); - - //! Will return a random integer within a range. This is faster than `(int)RandomRange(x,y)` - //! These bounds are INCLUSIVE! - static int RandomIntRange(const int max, const int min); - - //! Will 'roll' a dice, returning `true` \f$100 * chance\f$ percent of the time. - static bool RandomChance(const double chance); //! Kind of like \f$sin(counter)\f$, but it oscillates over \f$[a,b]\f$ instead of \f$[-1,1]\f$, by a given speed. //! Given that \f$speed = 1\f$, the result will always be `a` if `counter` is even, and `b` if `counter` is uneven. @@ -58,12 +37,6 @@ namespace Eule static double Oscillate(const double a, const double b, const double counter, const double speed); private: - //! Will initialize the random number generator - static void InitRng(); - - static std::mt19937 rng; - static bool isRngInitialized; - // No instanciation! >:( Math(); }; diff --git a/Eule/Random.cpp b/Eule/Random.cpp new file mode 100644 index 0000000..af2ac16 --- /dev/null +++ b/Eule/Random.cpp @@ -0,0 +1,73 @@ +#include "Random.h" +#include + +using namespace Eule; + +// Checks if the random number generator is initialized. Does nothing if it is, initializes if it isn't. +#define MAKE_SURE_RNG_IS_INITIALIZED if (!isRngInitialized) InitRng(); + +void Random::InitRng() +{ + // Create truly random source (from hardware events) + std::random_device randomSource; + + // Generate enough truly random values to populate the entire state of the mersenne twister + std::array seedValues; + std::generate_n(seedValues.data(), seedValues.size(), std::ref(randomSource)); + std::seed_seq seedSequence(seedValues.begin(), seedValues.end()); + + // Seed the mersenne twister with these values + rng = std::mt19937(seedSequence); + + isRngInitialized = true; + + return; +} + +// Will return a random double between 0 and 1 +double Random::RandomFloat() +{ + MAKE_SURE_RNG_IS_INITIALIZED; + + return (rng() % 694206942069ll) / 694206942069.0; +} + +// Will return a random unsigned integer. +unsigned int Random::RandomUint() +{ + MAKE_SURE_RNG_IS_INITIALIZED; + + return rng(); +} + +// Will return a random integer +unsigned int Random::RandomInt() +{ + MAKE_SURE_RNG_IS_INITIALIZED; + + // Since this is supposed to return a random value anyways, + // we can let the random uint overflow without any problems. + return (int)rng(); +} + +// Will return a random double within a range +// These bounds are INCLUSIVE! +double Random::RandomRange(double min, double max) +{ + return (RandomFloat() * (max - min)) + min; +} + +// Will return a random integer within a range. This is faster than '(int)RandomRange(x,y)' +// These bounds are INCLUSIVE! +int Random::RandomIntRange(int min, int max) +{ + return (rng() % (max + 1 - min)) + min; +} + +bool Random::RandomChance(const double chance) +{ + return RandomFloat() <= chance; +} + +std::mt19937 Random::rng; +bool Random::isRngInitialized = true; diff --git a/Eule/Random.h b/Eule/Random.h new file mode 100644 index 0000000..912a5f8 --- /dev/null +++ b/Eule/Random.h @@ -0,0 +1,41 @@ +#pragma once +#include + +namespace Eule +{ + /** Extensive random number generator + */ + class Random + { + public: + //! Will return a random double between `0` and `1` + static double RandomFloat(); + + //! Will return a random unsigned integer. + static unsigned int RandomUint(); + + //! Will return a random integer + static unsigned int RandomInt(); + + //! Will return a random double within a range + //! These bounds are INCLUSIVE! + static double RandomRange(const double min, const double max); + + //! Will return a random integer within a range. This is faster than `(int)RandomRange(x,y)` + //! These bounds are INCLUSIVE! + static int RandomIntRange(const int max, const int min); + + //! Will 'roll' a dice, returning `true` \f$100 * chance\f$ percent of the time. + static bool RandomChance(const double chance); + + private: + //! Will initialize the random number generator + static void InitRng(); + + static std::mt19937 rng; + static bool isRngInitialized; + + // No instanciation! >:( + Random(); + }; +} diff --git a/Test/Math__Oscillate.cpp b/Test/Math__Oscillate.cpp index 9268e6e..686ab9d 100644 --- a/Test/Math__Oscillate.cpp +++ b/Test/Math__Oscillate.cpp @@ -1,5 +1,6 @@ #include "CppUnitTest.h" #include "../_TestingUtilities/Testutil.h" +#include "../Eule/Random.h" #include "../Eule/Math.h" #include "../Eule/Constants.h" #include @@ -21,7 +22,7 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double rnd = Math::RandomRange(-1000, 1000); + const double rnd = Random::RandomRange(-1000, 1000); // Exercise const double result = Math::Oscillate(-1, 1, rnd, 1); @@ -41,9 +42,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1000, 1000); - const double b = Math::RandomRange(-1000, 1000); - const int even = Math::RandomIntRange(-1000, 1000) & ~1; + const double a = Random::RandomRange(-1000, 1000); + const double b = Random::RandomRange(-1000, 1000); + const int even = Random::RandomIntRange(-1000, 1000) & ~1; // Exercise const double result = Math::Oscillate(a, b, even, 1); @@ -70,9 +71,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1000, 1000); - const double b = Math::RandomRange(-1000, 1000); - const int uneven = Math::RandomIntRange(-1000, 1000) | 1; + const double a = Random::RandomRange(-1000, 1000); + const double b = Random::RandomRange(-1000, 1000); + const int uneven = Random::RandomIntRange(-1000, 1000) | 1; // Exercise const double result = Math::Oscillate(a, b, uneven, 1); @@ -90,9 +91,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1000, 1000); - const double b = Math::RandomRange(-1000, 1000); - const int anInt = Math::RandomIntRange(-1000, 1000); + const double a = Random::RandomRange(-1000, 1000); + const double b = Random::RandomRange(-1000, 1000); + const int anInt = Random::RandomIntRange(-1000, 1000); // Exercise const double result = Math::Oscillate(a, b, anInt + 0.5, 1); @@ -118,9 +119,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1, 1); - const double b = Math::RandomRange(-1, 1); - const int even = Math::RandomIntRange(-1000, 1000) & ~1; + const double a = Random::RandomRange(-1, 1); + const double b = Random::RandomRange(-1, 1); + const int even = Random::RandomIntRange(-1000, 1000) & ~1; // Exercise const double result = Math::Oscillate(a, b, even + 0.25, 1); @@ -148,9 +149,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1, 1); - const double b = Math::RandomRange(-1, 1); - const int even = Math::RandomIntRange(-1000, 1000) & ~1; + const double a = Random::RandomRange(-1, 1); + const double b = Random::RandomRange(-1, 1); + const int even = Random::RandomIntRange(-1000, 1000) & ~1; // Exercise const double result = Math::Oscillate(a, b, even + 0.75, 1); @@ -170,9 +171,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1, 1); - const double b = Math::RandomRange(-1, 1); - const int uneven = Math::RandomIntRange(-1000, 1000) | 1; + const double a = Random::RandomRange(-1, 1); + const double b = Random::RandomRange(-1, 1); + const int uneven = Random::RandomIntRange(-1000, 1000) | 1; // Exercise const double result = Math::Oscillate(a, b, uneven + 0.25, 1); @@ -192,9 +193,9 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1, 1); - const double b = Math::RandomRange(-1, 1); - const int uneven = Math::RandomIntRange(-1000, 1000) | 1; + const double a = Random::RandomRange(-1, 1); + const double b = Random::RandomRange(-1, 1); + const int uneven = Random::RandomIntRange(-1000, 1000) | 1; // Exercise const double result = Math::Oscillate(a, b, uneven + 0.75, 1); @@ -214,8 +215,8 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { // Setup - const double a = Math::RandomRange(-1000, 1000); - const double b = Math::RandomRange(-1000, 1000); + const double a = Random::RandomRange(-1000, 1000); + const double b = Random::RandomRange(-1000, 1000); // Exercise const double result = Math::Oscillate(a, b, 0.5, 2); diff --git a/Test/Random.cpp b/Test/Random.cpp new file mode 100644 index 0000000..6ebb060 --- /dev/null +++ b/Test/Random.cpp @@ -0,0 +1 @@ +#include "Random.h" diff --git a/Test/Random.h b/Test/Random.h new file mode 100644 index 0000000..7349666 --- /dev/null +++ b/Test/Random.h @@ -0,0 +1,41 @@ +#pragma once +#include + +namespace Eule +{ + /** Extensive random number generator + */ + class Random + { + public: + //! Will return a random double between `0` and `1` + static double Rand(); + + //! Will return a random unsigned integer. + static unsigned int RandomUint(); + + //! Will return a random integer + static unsigned int RandomInt(); + + //! Will return a random double within a range + //! These bounds are INCLUSIVE! + static double RandomRange(const double min, const double max); + + //! Will return a random integer within a range. This is faster than `(int)RandomRange(x,y)` + //! These bounds are INCLUSIVE! + static int RandomIntRange(const int max, const int min); + + //! Will 'roll' a dice, returning `true` \f$100 * chance\f$ percent of the time. + static bool RandomChance(const double chance); + + private: + //! Will initialize the random number generator + static void InitRng(); + + static std::mt19937 rng; + static bool isRngInitialized; + + // No instanciation! >:( + Random(); + }; +} diff --git a/Test/Math_RandomIntRange.cpp b/Test/Random_RandomIntRange.cpp similarity index 85% rename from Test/Math_RandomIntRange.cpp rename to Test/Random_RandomIntRange.cpp index 2b32d37..9591665 100644 --- a/Test/Math_RandomIntRange.cpp +++ b/Test/Random_RandomIntRange.cpp @@ -1,13 +1,13 @@ #include "CppUnitTest.h" #include "../_TestingUtilities/Testutil.h" -#include "../Eule/Math.h" +#include "../Eule/Random.h" #include #include using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Eule; -namespace _Math +namespace _Random { TEST_CLASS(_RandomIntRange) { @@ -18,7 +18,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - int rnd = Math::RandomIntRange(49, 99); + int rnd = Random::RandomIntRange(49, 99); Assert::IsTrue(rnd >= 49, L"rnd too small"); Assert::IsTrue(rnd <= 99, L"rnd too big"); @@ -33,7 +33,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - int rnd = Math::RandomIntRange(-39, 99); + int rnd = Random::RandomIntRange(-39, 99); Assert::IsTrue(rnd >= -39, L"rnd too small"); Assert::IsTrue(rnd <= 99, L"rnd too big"); @@ -48,7 +48,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - int rnd = Math::RandomIntRange(-39, -10); + int rnd = Random::RandomIntRange(-39, -10); Assert::IsTrue(rnd >= -39, L"rnd too small"); Assert::IsTrue(rnd <= -10, L"rnd too big"); @@ -68,7 +68,7 @@ namespace _Math for (std::size_t i = 0; i < 1000; i++) { - int randomVal = Math::RandomIntRange(0, 9); + int randomVal = Random::RandomIntRange(0, 9); foundDigits[randomVal] = true; } @@ -88,7 +88,7 @@ namespace _Math // Exercise // Create 1000 random values - std::generate_n(rands.data(), rands.size(), []()->int { return Math::RandomIntRange(100, (int)4e9); }); + std::generate_n(rands.data(), rands.size(), []()->int { return Random::RandomIntRange(100, (int)4e9); }); // Verify const double stddev = Testutil::Stddev(rands); diff --git a/Test/Math_Random.cpp b/Test/Random__RandomFloat.cpp similarity index 74% rename from Test/Math_Random.cpp rename to Test/Random__RandomFloat.cpp index 2a08fd2..40c128a 100644 --- a/Test/Math_Random.cpp +++ b/Test/Random__RandomFloat.cpp @@ -1,12 +1,12 @@ #include "CppUnitTest.h" -#include "../Eule/Math.h" +#include "../Eule/Random.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Eule; -namespace _Math +namespace _Random { - TEST_CLASS(_Random) + TEST_CLASS(_RandomFloat) { public: // Checks that all values are always 0 <= v <= 1 @@ -15,7 +15,7 @@ namespace _Math // Test 1000 random values for (std::size_t i = 0; i < 1e3; i++) { - const double rnd = Math::Random(); + const double rnd = Random::RandomFloat(); Assert::IsTrue(rnd >= 0.0, L"rnd < 0"); Assert::IsTrue(rnd <= 1.0, L"rnd > 1"); } diff --git a/Test/Math_RandomInteger.cpp b/Test/Random__RandomInteger.cpp similarity index 88% rename from Test/Math_RandomInteger.cpp rename to Test/Random__RandomInteger.cpp index ee60094..1b3ce13 100644 --- a/Test/Math_RandomInteger.cpp +++ b/Test/Random__RandomInteger.cpp @@ -1,13 +1,13 @@ #include "CppUnitTest.h" #include "../_TestingUtilities/Testutil.h" -#include "../Eule/Math.h" +#include "../Eule/Random.h" #include #include using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Eule; -namespace _Math +namespace _Random { TEST_CLASS(_RandomInteger) { @@ -21,7 +21,7 @@ namespace _Math // Exercise // Create 1000 random values - std::generate_n(rands.data(), rands.size(), []()->unsigned int { return Math::RandomUint(); }); + std::generate_n(rands.data(), rands.size(), []()->unsigned int { return Random::RandomUint(); }); // Verify const double stddev = Testutil::Stddev(rands); @@ -39,7 +39,7 @@ namespace _Math // Exercise // Create 1000 random values - std::generate_n(rands.data(), rands.size(), []()->int { return Math::RandomInt(); }); + std::generate_n(rands.data(), rands.size(), []()->int { return Random::RandomInt(); }); // Verify const double stddev = Testutil::Stddev(rands); diff --git a/Test/Math__RandomRange.cpp b/Test/Random__RandomRange.cpp similarity index 85% rename from Test/Math__RandomRange.cpp rename to Test/Random__RandomRange.cpp index cd5f957..03d7750 100644 --- a/Test/Math__RandomRange.cpp +++ b/Test/Random__RandomRange.cpp @@ -1,13 +1,13 @@ #include "CppUnitTest.h" #include "../_TestingUtilities/Testutil.h" -#include "../Eule/Math.h" +#include "../Eule/Random.h" #include #include using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Eule; -namespace _Math +namespace _Random { TEST_CLASS(_RandomRange) { @@ -19,7 +19,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - double rnd = Math::RandomRange(49.0, 99.0); + double rnd = Random::RandomRange(49.0, 99.0); Assert::IsTrue(rnd >= 49.0, L"rnd too small"); Assert::IsTrue(rnd <= 99.0, L"rnd too big"); @@ -34,7 +34,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - double rnd = Math::RandomRange(-39.0, 99.0); + double rnd = Random::RandomRange(-39.0, 99.0); Assert::IsTrue(rnd >= -39.0, L"rnd too small"); Assert::IsTrue(rnd <= 99.0, L"rnd too big"); @@ -49,7 +49,7 @@ namespace _Math // Test 1000 random integers for (std::size_t i = 0; i < 1000; i++) { - double rnd = Math::RandomRange(-39.0, -10.0); + double rnd = Random::RandomRange(-39.0, -10.0); Assert::IsTrue(rnd >= -39.0, L"rnd too small"); Assert::IsTrue(rnd <= -10.0, L"rnd too big"); @@ -67,7 +67,7 @@ namespace _Math // Exercise // Create 1000 random values - std::generate_n(rands.data(), rands.size(), []()->double { return Math::RandomRange(100, 4e9); }); + std::generate_n(rands.data(), rands.size(), []()->double { return Random::RandomRange(100, 4e9); }); // Verify const double stddev = Testutil::Stddev(rands); diff --git a/Test/_Test_Eule.vcxproj b/Test/_Test_Eule.vcxproj index 156e4c9..5dbe189 100644 --- a/Test/_Test_Eule.vcxproj +++ b/Test/_Test_Eule.vcxproj @@ -29,13 +29,13 @@ - - - + + + - + diff --git a/Test/_Test_Eule.vcxproj.filters b/Test/_Test_Eule.vcxproj.filters index 1368b38..7d45adf 100644 --- a/Test/_Test_Eule.vcxproj.filters +++ b/Test/_Test_Eule.vcxproj.filters @@ -19,14 +19,14 @@ {4af509be-a959-45e0-bec2-03894a16ad60} + + {b0dcb516-80a3-4bf7-99d7-50186d18e1ea} + Tests\Math - - Tests\Math - Tests\Math @@ -42,15 +42,6 @@ Tests\Math - - Tests\Math - - - Tests\Math - - - Tests\Math - Tests\Math @@ -78,5 +69,17 @@ Tests\Math + + Tests\Random + + + Tests\Random + + + Tests\Random + + + Tests\Random + \ No newline at end of file