Implement Trigonometric::SignOfSin, Trigonometric::SignOfCos, Trigonometric::SignOfTan,

Trigonometric::SignOfSin, and Trigonometric::QuadrantOf
This commit is contained in:
2024-12-11 01:34:12 -05:00
parent f4d8523bdc
commit 88dad23e50
2 changed files with 326 additions and 131 deletions

View File

@@ -17,18 +17,114 @@
#include <cassert>
#include <vector>
/// This set of functions may be set to use lookup tables or SIMD operations.
/// If no options are set, they will default to using standard library implementation.
#define USE_LOOKUP_TABLES /// Pre-computed lookup tables.
#undef USE_SSE /// Streaming SIMD Extensions (x86)
#undef USE_NEON /// ARM Vector Processing
#undef USE_AVX /// Advanced Vector Extensions (x86)
/// TODO: Implement lookup tables.
/// TODO: Implement constexpr Trigonometric LUT generators that are parameterized (samples, samples-per-period, etc.)
#ifdef USE_LOOKUP_TABLES
static float fast_cossin_table[MAX_CIRCLE_ANGLE];
#define LUT_SAMPLES 1024
#pragma region Trigonometric Lookup Tables
// Formula: sin(2*pi*t/T)
/** Generated using Dr LUT - Free Lookup Table Generator
* https://github.com/ppelikan/drlut
**/
// Formula: sin(2*pi*t/T)
const uint8_t u8_sin_lut[1024] = {
127,128,129,129,130,131,132,132,133,134,135,136,136,
137,138,139,139,140,141,142,143,143,144,145,146,146,
147,148,149,149,150,151,152,153,153,154,155,156,156,
157,158,159,159,160,161,162,162,163,164,165,165,166,
167,168,168,169,170,171,171,172,173,173,174,175,176,
176,177,178,178,179,180,181,181,182,183,183,184,185,
185,186,187,188,188,189,190,190,191,192,192,193,194,
194,195,196,196,197,198,198,199,199,200,201,201,202,
203,203,204,205,205,206,206,207,208,208,209,209,210,
211,211,212,212,213,213,214,215,215,216,216,217,217,
218,218,219,220,220,221,221,222,222,223,223,224,224,
225,225,226,226,227,227,228,228,229,229,229,230,230,
231,231,232,232,233,233,233,234,234,235,235,236,236,
236,237,237,238,238,238,239,239,239,240,240,240,241,
241,241,242,242,242,243,243,243,244,244,244,245,245,
245,245,246,246,246,247,247,247,247,248,248,248,248,
249,249,249,249,249,250,250,250,250,250,251,251,251,
251,251,251,252,252,252,252,252,252,252,253,253,253,
253,253,253,253,253,253,253,253,254,254,254,254,254,
254,254,254,254,254,254,254,254,254,254,254,254,254,
254,254,254,254,254,254,254,254,254,254,254,253,253,
253,253,253,253,253,253,253,253,253,252,252,252,252,
252,252,252,251,251,251,251,251,251,250,250,250,250,
250,249,249,249,249,249,248,248,248,248,247,247,247,
247,246,246,246,245,245,245,245,244,244,244,243,243,
243,242,242,242,241,241,241,240,240,240,239,239,239,
238,238,238,237,237,236,236,236,235,235,234,234,233,
233,233,232,232,231,231,230,230,229,229,229,228,228,
227,227,226,226,225,225,224,224,223,223,222,222,221,
221,220,220,219,218,218,217,217,216,216,215,215,214,
213,213,212,212,211,211,210,209,209,208,208,207,206,
206,205,205,204,203,203,202,201,201,200,199,199,198,
198,197,196,196,195,194,194,193,192,192,191,190,190,
189,188,188,187,186,185,185,184,183,183,182,181,181,
180,179,178,178,177,176,176,175,174,173,173,172,171,
171,170,169,168,168,167,166,165,165,164,163,162,162,
161,160,159,159,158,157,156,156,155,154,153,153,152,
151,150,149,149,148,147,146,146,145,144,143,143,142,
141,140,139,139,138,137,136,136,135,134,133,132,132,
131,130,129,129,128,127,126,125,125,124,123,122,122,
121,120,119,118,118,117,116,115,115,114,113,112,111,
111,110,109,108,108,107,106,105,105,104,103,102,101,
101,100, 99, 98, 98, 97, 96, 95, 95, 94, 93, 92, 92,
91, 90, 89, 89, 88, 87, 86, 86, 85, 84, 83, 83, 82,
81, 81, 80, 79, 78, 78, 77, 76, 76, 75, 74, 73, 73,
72, 71, 71, 70, 69, 69, 68, 67, 66, 66, 65, 64, 64,
63, 62, 62, 61, 60, 60, 59, 58, 58, 57, 56, 56, 55,
55, 54, 53, 53, 52, 51, 51, 50, 49, 49, 48, 48, 47,
46, 46, 45, 45, 44, 43, 43, 42, 42, 41, 41, 40, 39,
39, 38, 38, 37, 37, 36, 36, 35, 34, 34, 33, 33, 32,
32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26,
25, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20,
20, 19, 19, 18, 18, 18, 17, 17, 16, 16, 16, 15, 15,
15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11,
10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7,
7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4,
4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6,
6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9,
10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14,
14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18, 18,
19, 19, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24,
25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30,
31, 31, 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, 37,
38, 38, 39, 39, 40, 41, 41, 42, 42, 43, 43, 44, 45,
45, 46, 46, 47, 48, 48, 49, 49, 50, 51, 51, 52, 53,
53, 54, 55, 55, 56, 56, 57, 58, 58, 59, 60, 60, 61,
62, 62, 63, 64, 64, 65, 66, 66, 67, 68, 69, 69, 70,
71, 71, 72, 73, 73, 74, 75, 76, 76, 77, 78, 78, 79,
80, 81, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89,
89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 98, 98,
99,100,101,101,102,103,104,105,105,106,107,108,108,
109,110,111,111,112,113,114,115,115,116,117,118,118,
119,120,121,122,122,123,124,125,125,126 };
#pragma endregion
#endif
#include <J3ML/Algorithm/Reinterpret.hpp>
/// Swaps two elements in-place without copying their data.
template <typename T>
void Swap(T &a, T &b)
@@ -38,35 +134,33 @@ void Swap(T &a, T &b)
b = std::move(temp);
}
/// Clean symbolic names for integers of specific size.
namespace J3ML::SizedIntegralTypes
{
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using s8 = int8_t;
using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
}
namespace J3ML::SizedFloatTypes
{
// TODO: Use C++23 <stdfloat>
using f16 = float;
using f32 = float;
using f64 = double;
using f128 = long double;
namespace J3ML {
/// Clean symbolic names for integers of specific size.
namespace SizedIntegralTypes {
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using s8 = int8_t;
using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
}
//using namespace SizedIntegralTypes; // Bring into J3ML namespace.
namespace SizedFloatTypes { // TODO: Use C++23 <stdfloat>
using f16 = float;
using f32 = float;
using f64 = double;
using f128 = long double;
}
//using namespace SizedFloatTypes; // Bring into J3ML namespace.
}
using namespace J3ML::SizedIntegralTypes;
using namespace J3ML::SizedFloatTypes;
namespace J3ML::Math::BitTwiddling
{
namespace J3ML::BitTwiddling {
/// Parses a string of form "011101010" to a u32
u32 BinaryStringToValue(const char* s);
@@ -74,43 +168,48 @@ namespace J3ML::Math::BitTwiddling
inline int CountBitsSet(u32 value);
}
namespace J3ML::Math {
enum class Quadrant { I, II, III, IV };
// Zero technically isn't a sign, but zero also isn't positive, or negative, so bite me.
enum class Sign { ZERO, POSITIVE, NEGATIVE};
// TODO: Implement "Wrappers" for most standard math functions.
// We want to later-on implement lookup tables and SSE as conditional macros.
namespace J3ML::Math::Constants {
/// sqrt(2pi) ^ -1
constexpr float RecipSqrt2Pi = 0.3989422804014326779399460599343818684758586311649346576659258296706579258993018385012523339073069364;
/// pi - https://www.mathsisfun.com/numbers/pi.html
constexpr float Pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
/// e - https://www.mathsisfun.com/numbers/e-eulers-number.html
constexpr float EulersNumber = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274;
/// 2pi - The ratio of a circle's circumferecne to its radius, and the number of radians in one turn.
constexpr float Tau = 6.28318530717958647692;
/// sqrt(2)
constexpr float PythagorasConstant = 1.41421356237309504880;
/// sqrt(3)
constexpr float TheodorusConstant = 1.73205080756887729352;
/// Golden Ratio
constexpr float Phi = 1.61803398874989484820;
/// ln 2
constexpr float NaturalLog2 = 0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875;
/// ln 10
constexpr float NaturalLog10 = 2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983;
constexpr float Infinity = INFINITY;
constexpr float NegativeInfinity = -INFINITY;
constexpr float NotANumber = NAN;
}
/// This set of functions may be set to use lookup tables or SIMD operations.
/// If no options are set, they will default to using standard library implementation.
#undef USE_LOOKUP_TABLES /// Pre-computed lookup tables.
#undef USE_SSE /// Streaming SIMD Extensions (x86)
#undef USE_NEON /// ARM Vector Processing
#undef USE_AVX /// Advanced Vector Extensions (x86)
namespace J3ML::Math::Constants { // TODO: Consider double precision for these.
/// sqrt(2pi) ^ -1
constexpr float RecipSqrt2Pi = 0.3989422804014326779399460599343818684758586311649346576659258296706579258993018385012523339073069364;
/// pi - https://www.mathsisfun.com/numbers/pi.html
constexpr float Pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
constexpr float TwoPi = Pi*2.0;
constexpr float PiOverTwo = Pi/2.0;
constexpr float ThreePiOverTwo = 3.0*Pi/2.0;
/// e - https://www.mathsisfun.com/numbers/e-eulers-number.html
constexpr float EulersNumber = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274;
/// 2pi - The ratio of a circle's circumferecne to its radius, and the number of radians in one turn.
constexpr float Tau = 6.28318530717958647692;
/// sqrt(2)
constexpr float PythagorasConstant = 1.41421356237309504880;
/// sqrt(3)
constexpr float TheodorusConstant = 1.73205080756887729352;
/// Golden Ratio
constexpr float Phi = 1.61803398874989484820;
/// ln 2
constexpr float NaturalLog2 = 0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875;
/// ln 10
constexpr float NaturalLog10 = 2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983;
constexpr float Infinity = INFINITY;
constexpr float NegativeInfinity = -INFINITY;
constexpr float NotANumber = NAN;
}
namespace J3ML::Math {
using namespace Constants; // Bring into J3ML::Math namespace.
}
namespace J3ML::Math::Functions {
// TODO: Implement "Wrappers" for most standard math functions.
// We want to later-on implement lookup tables and SSE as conditional macros.
/// Clamps the given input value to the range [min, max].
/** @see Clamp01(), Min(), Max(). */
@@ -221,26 +320,37 @@ namespace J3ML::Math::Functions {
inline bool IsInfinite(double d) { return (ReinterpretAs<u64>(d) << 1) == 0xFFE0000000000000ULL; }
namespace Trigonometric {
Sign SignOfSin(float radians);
Sign SignOfCos(float radians);
Sign SignOfTan(float radians);
float Radians(float deg); /// Converts the given amount of degrees into radians.
float Degrees(float rad); /// Converts the given amount of radians into degrees.
Quadrant QuadrantOf(float radians);
float Sin(float x); /// Computes the sine of x, in radians.
float Cos(float x); /// Computes the cosine of x, in radians.
float Tan(float x); /// Computes the tangent of x, in radians.
/// Simultaneously computes both sine and cosine of x, in radians.
/// This yields a small performance increase over computing them separately.
/// @see Sin(), Cos().
void SinCos(float x, float& outSin, float& outCos);
float Radians(float deg); /// Converts the given amount of degrees into radians.
float Degrees(float rad); /// Converts the given amount of radians into degrees.
float Asin(float x); /// Computes the inverse sine of x, in radians.
float Acos(float x); /// Computes the inverse cosine of x, in radians.
float Atan(float x); /// Computes the inverse tangent of x, in radians.
float Atan2(float y, float x); /// Computes the signed (principal value) inverse tangent of y/x, in radians.
float Sinh(float x); /// Computes the hyperbolic sine of x, in radians.
float Cosh(float x); /// Computes the hyperbolic cosine of x, in radians.
float Tanh(float x); /// Computes the hyperbolic tangent of x, in radians.
float Sin(float x); /// Computes the sine of x, in radians.
float Cos(float x); /// Computes the cosine of x, in radians.
float Tan(float x); /// Computes the tangent of x, in radians.
/// Simultaneously computes both sine and cosine of x, in radians.
/// This yields a small performance increase over computing them separately.
/// @see Sin(), Cos().
void SinCos(float x, float& outSin, float& outCos);
float Asin(float x); /// Computes the inverse sine of x, in radians.
float Acos(float x); /// Computes the inverse cosine of x, in radians.
float Atan(float x); /// Computes the inverse tangent of x, in radians.
float Atan2(float y, float x); /// Computes the signed (principal value) inverse tangent of y/x, in radians.
float Sinh(float x); /// Computes the hyperbolic sine of x, in radians.
float Cosh(float x); /// Computes the hyperbolic cosine of x, in radians.
float Tanh(float x); /// Computes the hyperbolic tangent of x, in radians.
}
using namespace Trigonometric;
bool IsPow2(u32 number); /// Returns true if the given number is a power of 2.
bool IsPow2(u64 number); /// Returns true if the given number is a power of 2.
@@ -338,33 +448,50 @@ namespace J3ML::Math::Functions {
float Recip(float x); /// Returns 1/x, the reciprocal of x.
float RecipFast(float x); /// Returns 1/x, the reciprocal of x, using a fast approximation (SSE rcp instruction).
}
namespace Interp
{
inline float SmoothStart(float t);
}
namespace J3ML::Math::Functions::Interpolation
{
inline float SmoothStart(float t);
}
namespace J3ML::Math {
using namespace Functions;
}
namespace J3ML::Math::Types {
struct Radians { // TODO: Fill in with relevant members.
float value;
float operator()() const { return value; }
};
struct Degrees { // TODO: Fill in with relevant members.
float value;
float operator()() const { return value; }
};
}
namespace J3ML::Math {
using namespace Math::Constants;
using namespace Math::Functions;
struct Rotation
{
public:
struct Rotation {
Rotation();
Rotation(float value);
Rotation(const Types::Radians& radians);
Rotation(const Types::Degrees& degrees);
float valueInRadians;
float ValueInRadians() const;
float ValueInDegrees() const;
float ValueInRadians() const { return valueInRadians; }
Types::Radians Radians() const { return {valueInRadians}; }
float Degrees() const { return Functions::Degrees(valueInRadians); }
Rotation operator+(const Rotation& rhs);
};
Rotation operator ""_rad(long double rads);
Rotation operator ""_radians(long double rads);
@@ -374,4 +501,3 @@ namespace J3ML::Math {
Rotation operator ""_degrees(long double rads);
}

View File

@@ -38,14 +38,106 @@ float PowUInt(float base, u32 exponent)
}
namespace J3ML
{
namespace J3ML::Math::Functions::Trigonometric {
enum Sign SignOfSin(float radians) {
enum Quadrant q = QuadrantOf(radians);
if (q == Quadrant::I || q == Quadrant::II)
return Sign::POSITIVE;
float Math::Functions::Radians(float degrees) { return degrees * (Pi/180.f); }
// ReSharper disable once CppDFAConstantConditions
if (q == Quadrant::II || q == Quadrant::IV)
return Sign::NEGATIVE;
float Math::Functions::Degrees(float radians) { return radians * (180.f/Pi); }
// ReSharper disable once CppDFAUnreachableCode
return Sign::ZERO;
}
enum Sign SignOfCos(float radians) {
enum Quadrant q = QuadrantOf(radians);
if (q == Quadrant::I || q == Quadrant::IV)
return Sign::POSITIVE;
// ReSharper disable once CppDFAConstantConditions
if (q == Quadrant::II || q == Quadrant::III)
return Sign::NEGATIVE;
// ReSharper disable once CppDFAUnreachableCode
return Sign::ZERO;
}
enum Sign SignOfTan(float radians) {
enum Quadrant q = QuadrantOf(radians);
if (q == Quadrant::I || q == Quadrant::III)
return Sign::POSITIVE;
// ReSharper disable once CppDFAConstantConditions
if (q == Quadrant::II || q == Quadrant::IV)
return Sign::NEGATIVE;
// ReSharper disable once CppDFAUnreachableCode
return Sign::ZERO;
}
Quadrant QuadrantOf(float radians) {
if (radians > ThreePiOverTwo) {
return Quadrant::IV;
} else if (radians >= Pi) {
return Quadrant::III;
} else if (radians >= PiOverTwo) {
return Quadrant::II;
} else {
return Quadrant::I;;
}
}
float Radians(float degrees) { return degrees * (Pi/180.f); }
float Degrees(float radians) { return radians * (180.f/Pi); }
float Sin(float x) {
#ifdef USE_LOOKUP_TABLES
#elif USE_SSE
#else
return std::sin(x);
#endif
}
float Cos(float x) {
#ifdef USE_LOOKUP_TABLES
#elif USE_SSE
#else
return std::cos(x);
#endif
}
float Tan(float x) { return std::tan(x); }
void SinCos(float x, float &outSin, float &outCos) {
outSin = Sin(x);
outCos = Cos(x);
}
float Asin(float x) { return std::asin(x); }
float Acos(float x) { return std::acos(x); }
float Atan(float x) { return std::atan(x); }
float Atan2(float y, float x) { return std::atan2(y, x); }
float Sinh(float x) { return std::sinh(x); }
float Cosh(float x) { return std::cosh(x); }
float Tanh(float x) { return std::tanh(x); }
}
namespace J3ML::Math::Functions {
}
namespace J3ML {
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
@@ -211,56 +303,26 @@ namespace J3ML
Math::Rotation::Rotation(float value) : valueInRadians(value) {}
Math::Rotation::Rotation(const Types::Radians &radians): valueInRadians(radians.value) {}
Math::Rotation::Rotation(const Types::Degrees &degrees): valueInRadians(Functions::Radians(degrees.value)) {}
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) {
return {valueInRadians + rhs.valueInRadians};
}
float Math::Interp::SmoothStart(float t) {
assert(t >= 0.f && t <= 1.f);
return t*t;
}
int Math::BitTwiddling::CountBitsSet(u32 value) {
int BitTwiddling::CountBitsSet(u32 value) {
}
namespace Math::Functions {
float Sin(float x) {
#ifdef USE_LOOKUP_TABLES
#elif USE_SSE
#else
return std::sin(x);
#endif
}
float Cos(float x) {
#ifdef USE_LOOKUP_TABLES
#elif USE_SSE
#else
return std::cos(x);
#endif
}
float Tan(float x) { return std::tan(x); }
void SinCos(float x, float &outSin, float &outCos) {
outSin = Sin(x);
outCos = Cos(x);
}
float Asin(float x) { return std::asin(x); }
float Acos(float x) { return std::acos(x); }
float Atan(float x) { return std::atan(x); }
float Atan2(float y, float x) { return std::atan2(y, x); }
float Sinh(float x) { return std::sinh(x); }
float Cosh(float x) { return std::cosh(x); }
float Tanh(float x) { return std::tanh(x); }
bool IsPow2(u32 number) {
return (number & (number - 1)) == 0;
@@ -311,3 +373,10 @@ namespace J3ML
}
}
namespace J3ML::Math::Functions::Interpolation {
float SmoothStart(float t) {
assert(t >= 0.f && t <= 1.f);
return t*t;
}
}