Browse Source

public functions

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

61
src/Magnum/Math/Random.h

@ -17,78 +17,75 @@ namespace Magnum
namespace Math
{
namespace Implementation
namespace Random
{
class RandomGenerator
{
public:
RandomGenerator()
{
static std::seed_seq seeds{{
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
{
public:
RandomGenerator() = delete;
g = std::mt19937{seeds};
};
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(),
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>
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(),
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:
static std::mt19937 &generator()
{
static std::mt19937 g{seeds};
return g;
}
private:
// namespace Implementation
std::mt19937 g;
};
} // namespace Implementation
namespace Random
{
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),
return g.generate(static_cast<T>(begin),
static_cast<T>(end));
}
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)};
}
template <class T = Float>
Vector3<T> randomUnitVector3()
Vector3<T> 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<T>::pi());
auto z = randomScalar(-1.0f, -1.0f);
auto a = g.generate(0.0f, 2 * Math::Constants<T>::pi());
auto z = randomScalar(g, -1.0f, -1.0f);
auto r = sqrt<T>(1 - z * z);
return {r * std::cos(a), r * std::sin(a), z};
}
template <class T = Float>
Quaternion<T> randomRotation()
Quaternion<T> randomRotation(RandomGenerator &g)
{
//http://planning.cs.uiuc.edu/node198.html
auto u = randomScalar();
auto v = 2 * Math::Constants<T>::pi() * randomScalar();
auto w = 2 * Math::Constants<T>::pi() * randomScalar();
auto u = randomScalar(g);
auto v = 2 * Math::Constants<T>::pi() * randomScalar(g);
auto w = 2 * Math::Constants<T>::pi() * randomScalar(g);
return Quaternion<T>({sqrt<T>(1 - u) * std::sin(v),
sqrt<T>(1 - u) * std::cos(v),
sqrt<T>(u) * std::sin(w)},

20
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,28 +44,35 @@ RandomTest::RandomTest()
void RandomTest::randScalar()
{
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(-1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual);
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(-1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual);
Math::Random::RandomGenerator g;
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()
{
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.
@ -77,7 +85,7 @@ void RandomTest::randomDiceChiSquare()
std::vector<Int> faces(dice_side, 0);
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);
for (std::size_t i = 0; i < dice_side; i++)
residual[i] = Float(pow((faces[i] - expected), 2)) / expected;

Loading…
Cancel
Save