From 46a026e117a5d2a682c8ebfba3d68d3f52c8318d Mon Sep 17 00:00:00 2001 From: sariug Date: Sun, 5 Apr 2020 22:04:46 +0200 Subject: [PATCH 01/10] Initial Random.h --- src/Magnum/Math/CMakeLists.txt | 1 + src/Magnum/Math/Random.h | 125 +++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/Magnum/Math/Random.h diff --git a/src/Magnum/Math/CMakeLists.txt b/src/Magnum/Math/CMakeLists.txt index 749d824d7e..663c2ae861 100644 --- a/src/Magnum/Math/CMakeLists.txt +++ b/src/Magnum/Math/CMakeLists.txt @@ -49,6 +49,7 @@ set(MagnumMath_HEADERS Quaternion.h Packing.h PackingBatch.h + Random.h Range.h RectangularMatrix.h StrictWeakOrdering.h diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h new file mode 100644 index 0000000000..6cd1a2c5af --- /dev/null +++ b/src/Magnum/Math/Random.h @@ -0,0 +1,125 @@ +#ifndef Magnum_Math_Random_h +#define Magnum_Math_Random_h + +// TO DO Licence things. + +#include +#include +#include "Magnum/Types.h" +#include "Magnum/Math/Constants.h" +#include "Magnum/Math/Vector2.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Quaternion.h" +#include "Magnum/Math/Functions.h" + +namespace Magnum +{ +namespace Math +{ + +namespace Implementation +{ +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; + + template + static 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()); + } + + template + static 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()); + } + +public: + static std::mt19937 &generator() + { + static std::mt19937 g{seeds}; + return g; + } +}; +} // namespace Implementation +namespace Random +{ +template +T randomUnsignedScalar() // range [0, 1] +{ + return Implementation::RandomGenerator::generate(static_cast(0.0f), + static_cast(1.0f)); +} +template +T randomSignedScalar() // range [-1, 1] +{ + return Implementation::RandomGenerator::generate(static_cast(-1.0f), static_cast(1.0f)); +} + +template +Vector3 randomUnitVector2() +{ + auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants::pi()); + return {std::cos(a), std::sin(a)}; +} + +template +Vector3 randomUnitVector3() +{ + auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants::pi()); + auto z = randomSignedScalar(); + auto r = sqrt(1 - z * z); + return {r * std::cos(a), r * std::sin(a), z}; +} +template +Vector2 randomPointInACircle() // always length < 1 +{ + while (true) + { + auto p = Vector2( + randomSignedScalar(), randomSignedScalar()); + if (p.length() >= 1) + continue; + return p; + } +} + +template +Vector3 randomPointInASphere() // always length < 1 +{ + auto x = randomSignedScalar(); + auto y = randomSignedScalar(); + while (true) + { + auto p = Vector3(x, y, randomSignedScalar()); + if (p.length() >= 1) + continue; + return p; + } +} + +template +Quaternion randomRotation() +{ + return Quaternion({randomSignedScalar(), randomSignedScalar(), randomSignedScalar()}, randomSignedScalar()).normalized(); +} + +} // namespace Random + +} // namespace Math +} // namespace Magnum + +#endif From 8f73873d4134285ece3bad4327ce8d8b8e71d37f Mon Sep 17 00:00:00 2001 From: sariug Date: Mon, 6 Apr 2020 00:08:32 +0200 Subject: [PATCH 02/10] also some tests --- src/Magnum/Math/Random.h | 15 +++- src/Magnum/Math/Test/CMakeLists.txt | 6 ++ src/Magnum/Math/Test/RandomTest.cpp | 112 ++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 src/Magnum/Math/Test/RandomTest.cpp diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index 6cd1a2c5af..e0d335153b 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -11,6 +11,7 @@ #include "Magnum/Math/Vector3.h" #include "Magnum/Math/Quaternion.h" #include "Magnum/Math/Functions.h" +#include namespace Magnum { @@ -70,7 +71,7 @@ T randomSignedScalar() // range [-1, 1] } template -Vector3 randomUnitVector2() +Vector2 randomUnitVector2() { auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants::pi()); return {std::cos(a), std::sin(a)}; @@ -100,17 +101,23 @@ Vector2 randomPointInACircle() // always length < 1 template Vector3 randomPointInASphere() // always length < 1 { - auto x = randomSignedScalar(); - auto y = randomSignedScalar(); + while (true) { - auto p = Vector3(x, y, randomSignedScalar()); + auto p = Vector3(randomSignedScalar(), + randomSignedScalar(), + randomSignedScalar()); if (p.length() >= 1) continue; return p; } } +bool randomBool() +{ + return static_cast(randomUnsignedScalar()); +} + template Quaternion randomRotation() { diff --git a/src/Magnum/Math/Test/CMakeLists.txt b/src/Magnum/Math/Test/CMakeLists.txt index de48dbe704..873a0e95c9 100644 --- a/src/Magnum/Math/Test/CMakeLists.txt +++ b/src/Magnum/Math/Test/CMakeLists.txt @@ -70,6 +70,8 @@ corrade_add_test(MathStrictWeakOrderingTest StrictWeakOrderingTest.cpp LIBRARIES corrade_add_test(MathMatrixBenchmark MatrixBenchmark.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathRandomTest RandomTest.cpp LIBRARIES MagnumMathTestLib) + set_property(TARGET MathVectorTest MathMatrixTest @@ -85,6 +87,8 @@ set_property(TARGET MathDistanceTest MathIntersectionTest + + MathRandomTest APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") set_target_properties( @@ -130,4 +134,6 @@ set_target_properties( MathConfigurationValueTest MathStrictWeakOrderingTest + + MathRandomTest PROPERTIES FOLDER "Magnum/Math/Test") diff --git a/src/Magnum/Math/Test/RandomTest.cpp b/src/Magnum/Math/Test/RandomTest.cpp new file mode 100644 index 0000000000..6265c80ace --- /dev/null +++ b/src/Magnum/Math/Test/RandomTest.cpp @@ -0,0 +1,112 @@ +#include +#include + +#include "Magnum/Math/Random.h" + +namespace Magnum +{ +namespace Math +{ + +namespace Test +{ +namespace +{ + +struct RandomTest : Corrade::TestSuite::Tester +{ + explicit RandomTest(); + + void unsignedScalar(); + void signedScalar(); + void unitVector2(); + void unitVector3(); + void pointInACircle(); + void pointInASphere(); + void randomRotation(); +}; + +typedef Vector<2, Float> Vector2; +typedef Vector<3, Float> Vector3; +typedef Math::Constants Constants; + +RandomTest::RandomTest() +{ + addTests({&RandomTest::unsignedScalar, + &RandomTest::signedScalar, + &RandomTest::unitVector2, + &RandomTest::unitVector3, + &RandomTest::pointInACircle, + &RandomTest::pointInASphere, + &RandomTest::randomRotation}); +} + +// void RandomTest::construct() { +// constexpr Matrix4x4 a = {Vector4(3.0f, 5.0f, 8.0f, -3.0f), +// Vector4(4.5f, 4.0f, 7.0f, 2.0f), +// Vector4(1.0f, 2.0f, 3.0f, -1.0f), +// Vector4(7.9f, -1.0f, 8.0f, -1.5f)}; +// CORRADE_COMPARE(a, Matrix4x4(Vector4(3.0f, 5.0f, 8.0f, -3.0f), +// Vector4(4.5f, 4.0f, 7.0f, 2.0f), +// Vector4(1.0f, 2.0f, 3.0f, -1.0f), +// Vector4(7.9f, -1.0f, 8.0f, -1.5f))); + +// CORRADE_VERIFY((std::is_nothrow_constructible::value)); +// } +void RandomTest::unsignedScalar() +{ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_VERIFY(Math::Random::randomUnsignedScalar() < 1.000000001); + CORRADE_VERIFY(Math::Random::randomUnsignedScalar() > -.000000001); + } +} + +void RandomTest::signedScalar() +{ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_VERIFY(Math::Random::randomUnsignedScalar() < 1.000000001); + CORRADE_VERIFY(Math::Random::randomUnsignedScalar() > -1.000000001); + } +} + +void RandomTest::unitVector2() +{ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(),1.0f); + } +} +void RandomTest::unitVector3() +{ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(),1.0f); + } +} + +void RandomTest::pointInACircle(){ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_VERIFY((Math::Random::randomPointInACircle()).length()<1.0f); + } +} +void RandomTest::pointInASphere(){ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_VERIFY((Math::Random::randomPointInASphere()).length()<1.0f); + } +} +void RandomTest::randomRotation(){ + for (std::size_t i = 0; i < 10; i++) + { + CORRADE_COMPARE(Math::Random::randomRotation().length(), 1.0f); + } +} +} // namespace +} // namespace Test +} // namespace Math +} // namespace Magnum + +CORRADE_TEST_MAIN(Magnum::Math::Test::RandomTest) From 9de298734a1bb16a9f95550d84d13928246034a7 Mon Sep 17 00:00:00 2001 From: sariug Date: Mon, 6 Apr 2020 17:22:26 +0200 Subject: [PATCH 03/10] Get rid of iosteam. --- src/Magnum/Math/Random.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index e0d335153b..0bcacb885f 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -11,7 +11,6 @@ #include "Magnum/Math/Vector3.h" #include "Magnum/Math/Quaternion.h" #include "Magnum/Math/Functions.h" -#include namespace Magnum { From 282f3d5644c0e2a9e99512800682d31413ca39d0 Mon Sep 17 00:00:00 2001 From: sariug Date: Wed, 8 Apr 2020 22:49:40 +0200 Subject: [PATCH 04/10] add repeated tests, use better macros! --- src/Magnum/Math/Test/RandomTest.cpp | 73 +++++------------------------ 1 file changed, 13 insertions(+), 60 deletions(-) diff --git a/src/Magnum/Math/Test/RandomTest.cpp b/src/Magnum/Math/Test/RandomTest.cpp index 6265c80ace..e7364a84ef 100644 --- a/src/Magnum/Math/Test/RandomTest.cpp +++ b/src/Magnum/Math/Test/RandomTest.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "Magnum/Math/Random.h" @@ -17,12 +18,9 @@ struct RandomTest : Corrade::TestSuite::Tester { explicit RandomTest(); - void unsignedScalar(); void signedScalar(); void unitVector2(); void unitVector3(); - void pointInACircle(); - void pointInASphere(); void randomRotation(); }; @@ -32,77 +30,32 @@ typedef Math::Constants Constants; RandomTest::RandomTest() { - addTests({&RandomTest::unsignedScalar, - &RandomTest::signedScalar, - &RandomTest::unitVector2, - &RandomTest::unitVector3, - &RandomTest::pointInACircle, - &RandomTest::pointInASphere, - &RandomTest::randomRotation}); -} - -// void RandomTest::construct() { -// constexpr Matrix4x4 a = {Vector4(3.0f, 5.0f, 8.0f, -3.0f), -// Vector4(4.5f, 4.0f, 7.0f, 2.0f), -// Vector4(1.0f, 2.0f, 3.0f, -1.0f), -// Vector4(7.9f, -1.0f, 8.0f, -1.5f)}; -// CORRADE_COMPARE(a, Matrix4x4(Vector4(3.0f, 5.0f, 8.0f, -3.0f), -// Vector4(4.5f, 4.0f, 7.0f, 2.0f), -// Vector4(1.0f, 2.0f, 3.0f, -1.0f), -// Vector4(7.9f, -1.0f, 8.0f, -1.5f))); - -// CORRADE_VERIFY((std::is_nothrow_constructible::value)); -// } -void RandomTest::unsignedScalar() -{ - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_VERIFY(Math::Random::randomUnsignedScalar() < 1.000000001); - CORRADE_VERIFY(Math::Random::randomUnsignedScalar() > -.000000001); - } + Corrade::TestSuite::Tester::addRepeatedTests( + {&RandomTest::signedScalar, + &RandomTest::unitVector2, + &RandomTest::unitVector3, + &RandomTest::randomRotation}, + /*repeat number*/200); } void RandomTest::signedScalar() { - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_VERIFY(Math::Random::randomUnsignedScalar() < 1.000000001); - CORRADE_VERIFY(Math::Random::randomUnsignedScalar() > -1.000000001); - } + CORRADE_COMPARE_AS(Math::Random::randomSignedScalar(), 1.0f, Corrade::TestSuite::Compare::LessOrEqual); + CORRADE_COMPARE_AS(Math::Random::randomSignedScalar(), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual); } void RandomTest::unitVector2() { - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(),1.0f); - } + CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(), 1.0f); } void RandomTest::unitVector3() { - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(),1.0f); - } + CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(), 1.0f); } -void RandomTest::pointInACircle(){ - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_VERIFY((Math::Random::randomPointInACircle()).length()<1.0f); - } -} -void RandomTest::pointInASphere(){ - for (std::size_t i = 0; i < 10; i++) - { - CORRADE_VERIFY((Math::Random::randomPointInASphere()).length()<1.0f); - } -} -void RandomTest::randomRotation(){ - for (std::size_t i = 0; i < 10; i++) - { +void RandomTest::randomRotation() +{ CORRADE_COMPARE(Math::Random::randomRotation().length(), 1.0f); - } } } // namespace } // namespace Test From 9a0dffe625aa3ee63315b1653280089600bde05f Mon Sep 17 00:00:00 2001 From: sariug Date: Wed, 8 Apr 2020 22:50:05 +0200 Subject: [PATCH 05/10] Better quaternion, get rid of bool, put the links --- src/Magnum/Math/Random.h | 43 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index e0d335153b..0de59af8a1 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -80,48 +80,25 @@ Vector2 randomUnitVector2() template Vector3 randomUnitVector3() { + // 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 = randomSignedScalar(); auto r = sqrt(1 - z * z); return {r * std::cos(a), r * std::sin(a), z}; } -template -Vector2 randomPointInACircle() // always length < 1 -{ - while (true) - { - auto p = Vector2( - randomSignedScalar(), randomSignedScalar()); - if (p.length() >= 1) - continue; - return p; - } -} - -template -Vector3 randomPointInASphere() // always length < 1 -{ - - while (true) - { - auto p = Vector3(randomSignedScalar(), - randomSignedScalar(), - randomSignedScalar()); - if (p.length() >= 1) - continue; - return p; - } -} - -bool randomBool() -{ - return static_cast(randomUnsignedScalar()); -} template Quaternion randomRotation() { - return Quaternion({randomSignedScalar(), randomSignedScalar(), randomSignedScalar()}, randomSignedScalar()).normalized(); + //http://planning.cs.uiuc.edu/node198.html + auto u{randomUnsignedScalar()}; + auto v{2 * Math::Constants::pi() * randomUnsignedScalar()}; + auto w{2 * Math::Constants::pi() * randomUnsignedScalar()}; + return Quaternion({sqrt(1 - u) * std::sin(v), + sqrt(1 - u) * std::cos(v), + sqrt(u) * std::sin(w)}, + sqrt(u) * std::cos(w)); } } // namespace Random From 933721907bfedd2e28217c88544868729b517784 Mon Sep 17 00:00:00 2001 From: sariug Date: Wed, 8 Apr 2020 23:35:31 +0200 Subject: [PATCH 06/10] Mosra was right. --- src/Magnum/Math/Random.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index 28f3d90385..09d93fcea4 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -58,15 +58,10 @@ class RandomGenerator namespace Random { template -T randomUnsignedScalar() // range [0, 1] +T randomScalar(T begin = 0.0f, T end = 1.0f) { - return Implementation::RandomGenerator::generate(static_cast(0.0f), - static_cast(1.0f)); -} -template -T randomSignedScalar() // range [-1, 1] -{ - return Implementation::RandomGenerator::generate(static_cast(-1.0f), static_cast(1.0f)); + return Implementation::RandomGenerator::generate(static_cast(begin), + static_cast(end)); } template @@ -82,7 +77,7 @@ Vector3 randomUnitVector3() // 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 = randomSignedScalar(); + auto z = randomScalar(-1.0f, -1.0f); auto r = sqrt(1 - z * z); return {r * std::cos(a), r * std::sin(a), z}; } @@ -91,9 +86,9 @@ template Quaternion randomRotation() { //http://planning.cs.uiuc.edu/node198.html - auto u{randomUnsignedScalar()}; - auto v{2 * Math::Constants::pi() * randomUnsignedScalar()}; - auto w{2 * Math::Constants::pi() * randomUnsignedScalar()}; + auto u{randomScalar()}; + auto v{2 * Math::Constants::pi() * randomScalar()}; + auto w{2 * Math::Constants::pi() * randomScalar()}; return Quaternion({sqrt(1 - u) * std::sin(v), sqrt(1 - u) * std::cos(v), sqrt(u) * std::sin(w)}, From 3196dac7cd40900dd981ccfbab80b2d055d45278 Mon Sep 17 00:00:00 2001 From: sariug Date: Thu, 9 Apr 2020 18:52:28 +0200 Subject: [PATCH 07/10] ChiSquare is implemented. seems pretty neat ! --- src/Magnum/Math/Test/RandomTest.cpp | 49 +++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Magnum/Math/Test/RandomTest.cpp b/src/Magnum/Math/Test/RandomTest.cpp index e7364a84ef..3f9534a2ca 100644 --- a/src/Magnum/Math/Test/RandomTest.cpp +++ b/src/Magnum/Math/Test/RandomTest.cpp @@ -18,10 +18,11 @@ struct RandomTest : Corrade::TestSuite::Tester { explicit RandomTest(); - void signedScalar(); + void randScalar(); void unitVector2(); void unitVector3(); void randomRotation(); + void randomDiceChiSquare(); }; typedef Vector<2, Float> Vector2; @@ -31,32 +32,62 @@ typedef Math::Constants Constants; RandomTest::RandomTest() { Corrade::TestSuite::Tester::addRepeatedTests( - {&RandomTest::signedScalar, + {&RandomTest::randScalar, &RandomTest::unitVector2, &RandomTest::unitVector3, &RandomTest::randomRotation}, - /*repeat number*/200); + /*repeat number*/ 200); + Corrade::TestSuite::Tester::addTests( + {&RandomTest::randomDiceChiSquare}); } -void RandomTest::signedScalar() +void RandomTest::randScalar() { - CORRADE_COMPARE_AS(Math::Random::randomSignedScalar(), 1.0f, Corrade::TestSuite::Compare::LessOrEqual); - CORRADE_COMPARE_AS(Math::Random::randomSignedScalar(), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual); + 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); } void RandomTest::unitVector2() { - CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(), 1.0f); + CORRADE_COMPARE((Math::Random::randomUnitVector2()).length(), 1.0f); } void RandomTest::unitVector3() { - CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(), 1.0f); + CORRADE_COMPARE((Math::Random::randomUnitVector3()).length(), 1.0f); } void RandomTest::randomRotation() { - CORRADE_COMPARE(Math::Random::randomRotation().length(), 1.0f); + CORRADE_COMPARE(Math::Random::randomRotation().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 + + int error_count = 0; // We have 1 chance to over shoot. Thats why no repeated test. + + const Int dice_side = 20; + const Int expected = 10000; + const Float thresholdfor100 = 36.191; + + for (auto i = 0; i < 100; i++) + { + + 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)]++; + 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; + Float chi_square = std::accumulate(residual.begin(), residual.end(), 0.0); + if (chi_square > thresholdfor100) + error_count++; + } + CORRADE_COMPARE_AS(error_count, 2, Corrade::TestSuite::Compare::Less); +} + } // namespace } // namespace Test } // namespace Math From 7bcc433e5a3f94acc468273d19278e9dbda2f2af Mon Sep 17 00:00:00 2001 From: sariug Date: Sat, 11 Apr 2020 11:35:14 +0200 Subject: [PATCH 08/10] according to travis not all the compilers like initializer lists. --- src/Magnum/Math/Random.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magnum/Math/Random.h b/src/Magnum/Math/Random.h index 09d93fcea4..8f3c1234f9 100644 --- a/src/Magnum/Math/Random.h +++ b/src/Magnum/Math/Random.h @@ -86,9 +86,9 @@ template Quaternion randomRotation() { //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(); + auto v = 2 * Math::Constants::pi() * randomScalar(); + auto w = 2 * Math::Constants::pi() * randomScalar(); return Quaternion({sqrt(1 - u) * std::sin(v), sqrt(1 - u) * std::cos(v), sqrt(u) * std::sin(w)}, From c5e5804d730fe42621edbe39c418348acfbce80f Mon Sep 17 00:00:00 2001 From: sariug Date: Sat, 11 Apr 2020 12:13:52 +0200 Subject: [PATCH 09/10] 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 8f3c1234f9..e7457d4ee3 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 3f9534a2ca..f53aaf84bb 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; From ac524724bc5f12578489371b09611d28b889e755 Mon Sep 17 00:00:00 2001 From: sariug Date: Sat, 11 Apr 2020 12:45:17 +0200 Subject: [PATCH 10/10] no accumulate..MSVC dwants a header. --- src/Magnum/Math/Test/RandomTest.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Magnum/Math/Test/RandomTest.cpp b/src/Magnum/Math/Test/RandomTest.cpp index f53aaf84bb..043575a6fc 100644 --- a/src/Magnum/Math/Test/RandomTest.cpp +++ b/src/Magnum/Math/Test/RandomTest.cpp @@ -23,7 +23,6 @@ struct RandomTest : Corrade::TestSuite::Tester void unitVector3(); void randomRotation(); void randomDiceChiSquare(); - }; typedef Vector<2, Float> Vector2; @@ -51,19 +50,19 @@ void RandomTest::randScalar() void RandomTest::unitVector2() { - Math::Random::RandomGenerator g; + Math::Random::RandomGenerator g; CORRADE_COMPARE((Math::Random::randomUnitVector2(g)).length(), 1.0f); } void RandomTest::unitVector3() { - Math::Random::RandomGenerator g; + Math::Random::RandomGenerator g; CORRADE_COMPARE((Math::Random::randomUnitVector3(g)).length(), 1.0f); } void RandomTest::randomRotation() { - Math::Random::RandomGenerator g; + Math::Random::RandomGenerator g; CORRADE_COMPARE(Math::Random::randomRotation(g).length(), 1.0f); } @@ -82,14 +81,12 @@ void RandomTest::randomDiceChiSquare() for (auto i = 0; i < 100; i++) { - std::vector faces(dice_side, 0); for (std::size_t i = 0; i < expected * dice_side; i++) faces[Math::Random::randomScalar(g, 0, dice_side - 1)]++; - std::vector residual(dice_side, 0); + Float chi_square = 0.0f; for (std::size_t i = 0; i < dice_side; i++) - residual[i] = Float(pow((faces[i] - expected), 2)) / expected; - Float chi_square = std::accumulate(residual.begin(), residual.end(), 0.0); + chi_square += Float(pow((faces[i] - expected), 2)) / expected; if (chi_square > thresholdfor100) error_count++; }