Eule/Eule/Math.h
2021-11-15 16:10:07 +01:00

107 lines
3.5 KiB
C++

#pragma once
#include <random>
#include <stdexcept>
namespace Eule
{
/** Math utility class containing basic functions.
*/
class Math
{
public:
//! Will return the bigger of two values
[[nodiscard]] static constexpr double Max(const double a, const double b);
//! Will return the smaller of two values
[[nodiscard]] static constexpr double Min(const double a, const double b);
//! Will return `v`, but at least `min`, and at most `max`
[[nodiscard]] static constexpr double Clamp(const double v, const double min, const double max);
//! Will return the linear interpolation between `a` and `b` by `t`
[[nodiscard]] static constexpr double Lerp(double a, double b, double t);
//! Will return the absolute value of `a`
[[nodiscard]] static constexpr double Abs(const double a);
//! Compares two double values with a given accuracy
[[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`
static double Random();
//! Will return a random unsigned integer.
static unsigned int RandomUint();
//! Will return a random integer
static unsigned int RandomInt();
//! Will return a random double within a range
//! These bounds are INCLUSIVE!
static double RandomRange(const double min, const double max);
//! Will return a random integer within a range. This is faster than `(int)RandomRange(x,y)`
//! These bounds are INCLUSIVE!
static int RandomIntRange(const int max, const int min);
//! Will 'roll' a dice, returning `true` \f$100 * chance\f$ percent of the time.
static bool RandomChance(const double chance);
//! Kind of like \f$sin(counter)\f$, but it oscillates over \f$[a,b]\f$ instead of \f$[-1,1]\f$, by a given speed.
//! Given that \f$speed = 1\f$, the result will always be `a` if `counter` is even, and `b` if `counter` is uneven.
//! If `counter` is a rational, the result will oscillate between `a` and `b`, like `sin()` does.
//! If you increase `speed`, the oscillation frequency will increase. Meaning \f$speed = 2\f$ would result in \f$counter=0.5\f$ returning `b`.
static double Oscillate(const double a, const double b, const double counter, const double speed);
private:
//! Will initialize the random number generator
static void InitRng();
static std::mt19937 rng;
static bool isRngInitialized;
// No instanciation! >:(
Math();
};
/* These are just the inline methods. They have to lie in the header file. */
/* The more sophisticated methods are in the .cpp */
constexpr inline double Math::Max(double a, double b)
{
return (a > b) ? a : b;
}
constexpr inline double Math::Min(double a, double b)
{
return (a < b) ? a : b;
}
constexpr inline double Math::Clamp(double v, double min, double max)
{
return Max(Min(v, max), min);
}
constexpr inline double Math::Lerp(double a, double b, double t)
{
const double it = 1.0 - t;
return (a * it) + (b * t);
}
constexpr inline double Math::Abs(const double a)
{
return (a > 0.0) ? a : -a;
}
constexpr inline bool Math::Similar(const double a, const double b, const double epsilon)
{
return Abs(a - b) <= epsilon;
}
}