From c5e5804d730fe42621edbe39c418348acfbce80f Mon Sep 17 00:00:00 2001 From: sariug Date: Sat, 11 Apr 2020 12:13:52 +0200 Subject: [PATCH] public functions --- src/Magnum/Math/Random.h | 67 ++++++++++++++--------------- src/Magnum/Math/Test/RandomTest.cpp | 22 +++++++--- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index 8f3c1234f..e7457d4ee 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -17,78 +17,75 @@ namespace Magnum namespace Math { -namespace Implementation +namespace Random { -static std::seed_seq seeds{{ - static_cast(std::random_device{}()), - static_cast(std::chrono::steady_clock::now() - .time_since_epoch() - .count()), -}}; - class RandomGenerator { public: - RandomGenerator() = delete; - + RandomGenerator() + { + std::seed_seq seeds{{ + static_cast(std::random_device{}()), + static_cast(std::chrono::steady_clock::now() + .time_since_epoch() + .count()), + }}; + g = std::mt19937{seeds}; + }; template - static typename std::enable_if::value, T>::type + typename std::enable_if::value, T>::type generate(T start = -Magnum::Math::Constants::inf(), T end = Magnum::Math::Constants::inf()) { - return std::uniform_int_distribution{start, end}(generator()); + return std::uniform_int_distribution{start, end}(g); } template - static typename std::enable_if::value, T>::type + typename std::enable_if::value, T>::type generate(T start = -Magnum::Math::Constants::inf(), T end = Magnum::Math::Constants::inf()) { - return std::uniform_real_distribution{start, end}(generator()); + return std::uniform_real_distribution{start, end}(g); } -public: - static std::mt19937 &generator() - { - static std::mt19937 g{seeds}; - return g; - } +private: + // namespace Implementation + std::mt19937 g; }; -} // namespace Implementation -namespace Random -{ + template -T randomScalar(T begin = 0.0f, T end = 1.0f) +T randomScalar(RandomGenerator &g, T begin = 0.0f, T end = 1.0f) { - return Implementation::RandomGenerator::generate(static_cast(begin), - static_cast(end)); + + return g.generate(static_cast(begin), + static_cast(end)); } template -Vector2 randomUnitVector2() +Vector2 randomUnitVector2(RandomGenerator &g) { - auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants::pi()); + auto a = g.generate(0.0f, 2 * Math::Constants::pi()); return {std::cos(a), std::sin(a)}; } template -Vector3 randomUnitVector3() +Vector3 randomUnitVector3(RandomGenerator &g) { // Better to have it "theta" and "z" than three random numbers. // https://mathworld.wolfram.com/SpherePointPicking.html - auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants::pi()); - auto z = randomScalar(-1.0f, -1.0f); + auto a = g.generate(0.0f, 2 * Math::Constants::pi()); + auto z = randomScalar(g, -1.0f, -1.0f); auto r = sqrt(1 - z * z); return {r * std::cos(a), r * std::sin(a), z}; } template -Quaternion randomRotation() +Quaternion randomRotation(RandomGenerator &g) { //http://planning.cs.uiuc.edu/node198.html - auto u = randomScalar(); - auto v = 2 * Math::Constants::pi() * randomScalar(); - auto w = 2 * Math::Constants::pi() * randomScalar(); + auto u = randomScalar(g); + auto v = 2 * Math::Constants::pi() * randomScalar(g); + auto w = 2 * Math::Constants::pi() * randomScalar(g); return Quaternion({sqrt(1 - u) * std::sin(v), sqrt(1 - u) * std::cos(v), sqrt(u) * std::sin(w)}, diff --git a/src/Magnum/Math/Test/RandomTest.cpp b/src/Magnum/Math/Test/RandomTest.cpp index 3f9534a2c..f53aaf84b 100644 --- a/src/Magnum/Math/Test/RandomTest.cpp +++ b/src/Magnum/Math/Test/RandomTest.cpp @@ -23,6 +23,7 @@ struct RandomTest : Corrade::TestSuite::Tester void unitVector3(); void randomRotation(); void randomDiceChiSquare(); + }; typedef Vector<2, Float> Vector2; @@ -43,29 +44,36 @@ RandomTest::RandomTest() void RandomTest::randScalar() { - CORRADE_COMPARE_AS(Math::Random::randomScalar(-1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual); - CORRADE_COMPARE_AS(Math::Random::randomScalar(-1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual); + Math::Random::RandomGenerator g; + CORRADE_COMPARE_AS(Math::Random::randomScalar(g, -1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual); + CORRADE_COMPARE_AS(Math::Random::randomScalar(g, -1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual); } void RandomTest::unitVector2() { - CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(), 1.0f); + Math::Random::RandomGenerator g; + CORRADE_COMPARE((Math::Random::randomUnitVector2(g)).length(), 1.0f); } void RandomTest::unitVector3() { - CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(), 1.0f); + Math::Random::RandomGenerator g; + + CORRADE_COMPARE((Math::Random::randomUnitVector3(g)).length(), 1.0f); } void RandomTest::randomRotation() { - CORRADE_COMPARE(Math::Random::randomRotation().length(), 1.0f); + Math::Random::RandomGenerator g; + + CORRADE_COMPARE(Math::Random::randomRotation(g).length(), 1.0f); } void RandomTest::randomDiceChiSquare() { // A step by step explanation // https://rpg.stackexchange.com/questions/70802/how-can-i-test-whether-a-die-is-fair - + Math::Random::RandomGenerator g; + int error_count = 0; // We have 1 chance to over shoot. Thats why no repeated test. const Int dice_side = 20; @@ -77,7 +85,7 @@ void RandomTest::randomDiceChiSquare() std::vector faces(dice_side, 0); for (std::size_t i = 0; i < expected * dice_side; i++) - faces[Math::Random::randomScalar(0, dice_side - 1)]++; + faces[Math::Random::randomScalar(g, 0, dice_side - 1)]++; std::vector residual(dice_side, 0); for (std::size_t i = 0; i < dice_side; i++) residual[i] = Float(pow((faces[i] - expected), 2)) / expected;