Added Math::Mod method

This commit is contained in:
Leonetienne 2021-11-15 16:10:07 +01:00
parent e699a20f11
commit 6926ebab1c
5 changed files with 111 additions and 0 deletions

View File

@ -75,5 +75,24 @@ bool Math::RandomChance(const double chance)
return Random() <= chance; return Random() <= chance;
} }
int Math::Mod(const int numerator, const int denominator)
{
if (denominator == 0)
throw std::logic_error("Divide by zero");
// Quick optimizations:
// -> 0/n is always 0
if (numerator == 0)
return 0;
// -> operator% works for a > 0 && b > 0
if (denominator > 0 && numerator > 0)
return numerator % denominator;
// Else: generalized formula
return (denominator + (numerator % denominator)) % denominator;
}
std::mt19937 Math::rng; std::mt19937 Math::rng;
bool Math::isRngInitialized = true; bool Math::isRngInitialized = true;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <random> #include <random>
#include <stdexcept>
namespace Eule namespace Eule
{ {
@ -26,6 +27,10 @@ namespace Eule
//! Compares two double values with a given accuracy //! Compares two double values with a given accuracy
[[nodiscard]] static constexpr bool Similar(const double a, const double b, const double epsilon = 0.00001); [[nodiscard]] static constexpr bool Similar(const double a, const double b, const double epsilon = 0.00001);
//! Will compute the actual modulo of a fraction. The % operator returns bs for n<0.
//! May throw divide-by-zero std::logic_error
[[nodiscard]] static int Mod(const int numerator, const int denominator);
//! Will return a random double between `0` and `1` //! Will return a random double between `0` and `1`
static double Random(); static double Random();

83
Test/Math__Mod.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "CppUnitTest.h"
#include "../Eule/Math.h"
#include <stdexcept>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Eule;
/** Equivalence classes:
* a -> numerator
* b -> denominator
* -- a > 0 && b > 0
* -- a < 0 && b > 0
* -- a > 0 && b < 0
* -- a < 0 && b < 0
*
* -- a > 0 && b = 0
* -- a = 0 && b > 0
* * -- a < 0 && b = 0
* -- a = 0 && b < 0
* -- a = 0 && b = 0
*/
namespace _Math
{
TEST_CLASS(_Mod)
{
public:
// a > 0 && b > 0
TEST_METHOD(a_gt_0_and_b_gt_0)
{
Assert::AreEqual(7, Math::Mod(199, 32));
return;
}
// a < 0 && b > 0
TEST_METHOD(a_lt_0_and_b_gt_0)
{
Assert::AreEqual(25, Math::Mod(-199, 32));
return;
}
// a > 0 && b < 0
TEST_METHOD(a_gt_0_and_b_lt_0)
{
Assert::AreEqual(-25, Math::Mod(199, -32));
return;
}
// a > 0 && b = 0
TEST_METHOD(a_gt_0_and_b_eq_0)
{
// Exppect divide-by-zero
Assert::ExpectException<std::logic_error&>([]() {
Assert::AreEqual(0, Math::Mod(199, 0));
});
return;
}
// a = 0 && b > 0
TEST_METHOD(a_eq_0_and_b_gt_0)
{
Assert::AreEqual(0, Math::Mod(0, 32));
return;
}
// a < 0 && b = 0
TEST_METHOD(a_lt_0_and_b_eq_0)
{
// Exppect divide-by-zero
Assert::ExpectException<std::logic_error&>([]() {
Assert::AreEqual(0, Math::Mod(-199, 0));
});
return;
}
// a = 0 && b < 0
TEST_METHOD(a_eq_0_and_b_lt_0)
{
Assert::AreEqual(0, Math::Mod(0, -32));
return;
}
};
}

View File

@ -33,6 +33,7 @@
<ClCompile Include="Math_RandomInteger.cpp" /> <ClCompile Include="Math_RandomInteger.cpp" />
<ClCompile Include="Math_RandomIntRange.cpp" /> <ClCompile Include="Math_RandomIntRange.cpp" />
<ClCompile Include="Math_Similar.cpp" /> <ClCompile Include="Math_Similar.cpp" />
<ClCompile Include="Math__Mod.cpp" />
<ClCompile Include="Math__Oscillate.cpp" /> <ClCompile Include="Math__Oscillate.cpp" />
<ClCompile Include="Math__RandomRange.cpp" /> <ClCompile Include="Math__RandomRange.cpp" />
<ClCompile Include="Matrix4x4.cpp" /> <ClCompile Include="Matrix4x4.cpp" />

View File

@ -75,5 +75,8 @@
<ClCompile Include="TrapazoidalPrismCollider.cpp"> <ClCompile Include="TrapazoidalPrismCollider.cpp">
<Filter>Tests</Filter> <Filter>Tests</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Math__Mod.cpp">
<Filter>Tests\Math</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>