Browse Source

public functions

pull/432/head
sariug 6 years ago
parent
commit
c5e5804d73
  1. 67
      src/Magnum/Math/Random.h
  2. 22
      src/Magnum/Math/Test/RandomTest.cpp

67
src/Magnum/Math/Random.h

@ -17,78 +17,75 @@ namespace Magnum
namespace Math namespace Math
{ {
namespace Implementation namespace Random
{ {
static std::seed_seq seeds{{
static_cast<std::uintmax_t>(std::random_device{}()),
static_cast<std::uintmax_t>(std::chrono::steady_clock::now()
.time_since_epoch()
.count()),
}};
class RandomGenerator class RandomGenerator
{ {
public: public:
RandomGenerator() = delete; RandomGenerator()
{
std::seed_seq seeds{{
static_cast<std::uintmax_t>(std::random_device{}()),
static_cast<std::uintmax_t>(std::chrono::steady_clock::now()
.time_since_epoch()
.count()),
}};
g = std::mt19937{seeds};
};
template <typename T> template <typename T>
static typename std::enable_if<std::is_same<Int, T>::value, T>::type typename std::enable_if<std::is_same<Int, T>::value, T>::type
generate(T start = -Magnum::Math::Constants<T>::inf(), generate(T start = -Magnum::Math::Constants<T>::inf(),
T end = Magnum::Math::Constants<T>::inf()) T end = Magnum::Math::Constants<T>::inf())
{ {
return std::uniform_int_distribution<T>{start, end}(generator()); return std::uniform_int_distribution<T>{start, end}(g);
} }
template <typename T> template <typename T>
static typename std::enable_if<std::is_same<Float, T>::value, T>::type typename std::enable_if<std::is_same<Float, T>::value, T>::type
generate(T start = -Magnum::Math::Constants<T>::inf(), generate(T start = -Magnum::Math::Constants<T>::inf(),
T end = Magnum::Math::Constants<T>::inf()) T end = Magnum::Math::Constants<T>::inf())
{ {
return std::uniform_real_distribution<T>{start, end}(generator()); return std::uniform_real_distribution<T>{start, end}(g);
} }
public: private:
static std::mt19937 &generator() // namespace Implementation
{ std::mt19937 g;
static std::mt19937 g{seeds};
return g;
}
}; };
} // namespace Implementation
namespace Random
{
template <class T = Float> template <class T = Float>
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<T>(begin),
static_cast<T>(end)); return g.generate(static_cast<T>(begin),
static_cast<T>(end));
} }
template <class T = Float> template <class T = Float>
Vector2<T> randomUnitVector2() Vector2<T> randomUnitVector2(RandomGenerator &g)
{ {
auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants<T>::pi()); auto a = g.generate(0.0f, 2 * Math::Constants<T>::pi());
return {std::cos(a), std::sin(a)}; return {std::cos(a), std::sin(a)};
} }
template <class T = Float> template <class T = Float>
Vector3<T> randomUnitVector3() Vector3<T> randomUnitVector3(RandomGenerator &g)
{ {
// Better to have it "theta" and "z" than three random numbers. // Better to have it "theta" and "z" than three random numbers.
// https://mathworld.wolfram.com/SpherePointPicking.html // https://mathworld.wolfram.com/SpherePointPicking.html
auto a = Implementation::RandomGenerator::generate(0.0f, 2 * Math::Constants<T>::pi()); auto a = g.generate(0.0f, 2 * Math::Constants<T>::pi());
auto z = randomScalar(-1.0f, -1.0f); auto z = randomScalar(g, -1.0f, -1.0f);
auto r = sqrt<T>(1 - z * z); auto r = sqrt<T>(1 - z * z);
return {r * std::cos(a), r * std::sin(a), z}; return {r * std::cos(a), r * std::sin(a), z};
} }
template <class T = Float> template <class T = Float>
Quaternion<T> randomRotation() Quaternion<T> randomRotation(RandomGenerator &g)
{ {
//http://planning.cs.uiuc.edu/node198.html //http://planning.cs.uiuc.edu/node198.html
auto u = randomScalar(); auto u = randomScalar(g);
auto v = 2 * Math::Constants<T>::pi() * randomScalar(); auto v = 2 * Math::Constants<T>::pi() * randomScalar(g);
auto w = 2 * Math::Constants<T>::pi() * randomScalar(); auto w = 2 * Math::Constants<T>::pi() * randomScalar(g);
return Quaternion<T>({sqrt<T>(1 - u) * std::sin(v), return Quaternion<T>({sqrt<T>(1 - u) * std::sin(v),
sqrt<T>(1 - u) * std::cos(v), sqrt<T>(1 - u) * std::cos(v),
sqrt<T>(u) * std::sin(w)}, sqrt<T>(u) * std::sin(w)},

22
src/Magnum/Math/Test/RandomTest.cpp

@ -23,6 +23,7 @@ struct RandomTest : Corrade::TestSuite::Tester
void unitVector3(); void unitVector3();
void randomRotation(); void randomRotation();
void randomDiceChiSquare(); void randomDiceChiSquare();
}; };
typedef Vector<2, Float> Vector2; typedef Vector<2, Float> Vector2;
@ -43,29 +44,36 @@ RandomTest::RandomTest()
void RandomTest::randScalar() void RandomTest::randScalar()
{ {
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(-1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual); Math::Random::RandomGenerator g;
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(-1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual); CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(g, -1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual);
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(g, -1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual);
} }
void RandomTest::unitVector2() 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() 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() 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() void RandomTest::randomDiceChiSquare()
{ {
// A step by step explanation // A step by step explanation
// https://rpg.stackexchange.com/questions/70802/how-can-i-test-whether-a-die-is-fair // 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. int error_count = 0; // We have 1 chance to over shoot. Thats why no repeated test.
const Int dice_side = 20; const Int dice_side = 20;
@ -77,7 +85,7 @@ void RandomTest::randomDiceChiSquare()
std::vector<Int> faces(dice_side, 0); std::vector<Int> faces(dice_side, 0);
for (std::size_t i = 0; i < expected * dice_side; i++) for (std::size_t i = 0; i < expected * dice_side; i++)
faces[Math::Random::randomScalar<Int>(0, dice_side - 1)]++; faces[Math::Random::randomScalar<Int>(g, 0, dice_side - 1)]++;
std::vector<Int> residual(dice_side, 0); std::vector<Int> residual(dice_side, 0);
for (std::size_t i = 0; i < dice_side; i++) for (std::size_t i = 0; i < dice_side; i++)
residual[i] = Float(pow((faces[i] - expected), 2)) / expected; residual[i] = Float(pow((faces[i] - expected), 2)) / expected;

Loading…
Cancel
Save