diff --git a/src/libs/karm-math/au.h b/src/libs/karm-math/au.h index acc87d4a5..96549ed7f 100644 --- a/src/libs/karm-math/au.h +++ b/src/libs/karm-math/au.h @@ -29,3 +29,7 @@ using RadiiAu = Math::Radii; constexpr Karm::Au operator""_au(unsigned long long val) { return Karm::Au{val}; } + +constexpr Karm::Au operator""_au(long double val) { + return Karm::Au{val}; +} diff --git a/src/libs/karm-math/fixed.h b/src/libs/karm-math/fixed.h index 953506ac7..8ac2b3a9c 100644 --- a/src/libs/karm-math/fixed.h +++ b/src/libs/karm-math/fixed.h @@ -3,6 +3,8 @@ #include #include +#include "funcs.h" + namespace Karm::Math { template @@ -159,7 +161,7 @@ struct _Fixed { constexpr _Frac<_Fixed> operator/(_Fixed const& rhs) const; - constexpr _Fixed operator/(_Frac<_Fixed> const& rhs) const; + constexpr _Frac<_Fixed> operator/(_Frac<_Fixed> const& rhs) const; constexpr _Fixed& operator+=(_Fixed const& rhs) { return *this = *this + rhs; @@ -177,6 +179,10 @@ struct _Fixed { return *this = *this / rhs; } + constexpr bool operator==(_Frac<_Fixed> const& rhs) const { + return _Fixed(rhs) == *this; + } + constexpr bool operator==(_Fixed const& rhs) const = default; constexpr std::strong_ordering operator<=>(_Fixed const& rhs) const = default; @@ -194,9 +200,26 @@ struct _Frac { _Frac(I num, I deno = 1) : _num(num), _deno(deno) {} + constexpr _Frac operator+(T const& rhs) const { + return _Frac(_num + (rhs * _deno), _deno); + } + + constexpr _Frac operator/(T const& rhs) const { + return _Frac(_num, _deno * rhs); + } + + constexpr bool operator==(_Frac const& rhs) const { + auto common = gcd(_deno._val, rhs._deno._val); + return _num._val / (_num._val / common) == rhs._num._val / (rhs._num._val / common); + } + constexpr operator T() const { return _num.loosyDiv(_deno); } + + void repr(Io::Emit& e) const { + e("{}/{}", _num, _deno); + } }; template @@ -205,8 +228,8 @@ constexpr _Frac<_Fixed> _Fixed::operator/(_Fixed const& rhs) c } template -constexpr _Fixed _Fixed::operator/(_Frac<_Fixed> const& rhs) const { - return fromRaw(saturatingDiv(_val, rhs._num) * rhs._deno); +constexpr _Frac<_Fixed> _Fixed::operator/(_Frac<_Fixed> const& rhs) const { + return _Frac<_Fixed>{fromRaw(_val) * rhs._deno, rhs._num}; } using i24f8 = _Fixed; diff --git a/src/libs/karm-math/funcs.h b/src/libs/karm-math/funcs.h index 110ccf6ad..4edd36a61 100644 --- a/src/libs/karm-math/funcs.h +++ b/src/libs/karm-math/funcs.h @@ -2,6 +2,7 @@ #include #include +#include #include "const.h" @@ -23,6 +24,16 @@ constexpr bool epsilonEq(T lhs, T rhs, T epsilon = Limits::EPSILON) { return abs(lhs - rhs) < epsilon; } +template +constexpr T gcd(T a, T b) { + while (b != 0) { + T tmp = a % b; + a = b; + b = tmp; + } + return a; +} + // MARK: Floats ---------------------------------------------------------------- static constexpr bool isNan(f64 x) { @@ -200,17 +211,26 @@ constexpr T pow(T a, T b) { template auto sqrt(T x) -> T { - if (x < 0.0) - return NAN; + if (x < T(0.0)) { + if constexpr (Meta::Float) + return NAN; + else + panic("Invalid sqrt"); + } - if (x == 0.0 or isNan(x) or isInf(x)) + if (x == T(0.0)) return x; - auto guess = x / 2; - auto last = guess + 1; + if constexpr (Meta::Float) { + if (isNan(x) or isInf(x)) + return x; + } + + auto guess = x / T(2); + auto last = guess + T(1); while (guess != last) { last = guess; - guess = (guess + x / guess) / 2; + guess = (guess + x / guess) / T(2); } return guess; } diff --git a/src/libs/karm-math/radii.h b/src/libs/karm-math/radii.h index d7cd5313c..4176ade7c 100644 --- a/src/libs/karm-math/radii.h +++ b/src/libs/karm-math/radii.h @@ -95,7 +95,7 @@ struct Radii { Radii reduceOverlap(Vec2 size) const { auto res = *this; auto scaleAll = [&](T factor) { - if (factor >= 1) + if (factor >= T(1)) return; for (auto& radii : res.radii) radii *= factor; @@ -105,16 +105,16 @@ struct Radii { r = max(r, T{}); auto sumTop = res.b + res.c; - scaleAll(sumTop > T{} ? size.width / sumTop : 1); + scaleAll(sumTop > T{} ? size.width / sumTop : T(1)); auto sumEnd = res.d + res.e; - scaleAll(sumEnd > T{} ? size.height / sumEnd : 1); + scaleAll(sumEnd > T{} ? size.height / sumEnd : T(1)); auto sumBottom = res.f + res.g; - scaleAll(sumBottom > T{} ? size.width / sumBottom : 1); + scaleAll(sumBottom > T{} ? size.width / sumBottom : T(1)); auto sumStart = res.h + res.a; - scaleAll(sumStart > T{} ? size.height / sumStart : 1); + scaleAll(sumStart > T{} ? size.height / sumStart : T(1)); return res; } diff --git a/src/libs/karm-math/rect.h b/src/libs/karm-math/rect.h index 343e8d887..321a43e84 100644 --- a/src/libs/karm-math/rect.h +++ b/src/libs/karm-math/rect.h @@ -80,8 +80,8 @@ union Rect { always_inline static constexpr Rect fromCenter(Vec2 center, Vec2 size) { return { - center.x - size.x / 2, - center.y - size.y / 2, + center.x - size.x / T(2), + center.y - size.y / T(2), size.x, size.y, }; @@ -125,15 +125,15 @@ union Rect { always_inline constexpr Vec2 bottomEnd() const { return {x + width, y + height}; } - always_inline constexpr Vec2 center() const { return {x + width / 2, y + height / 2}; } + always_inline constexpr Vec2 center() const { return {x + width / T(2), y + height / T(2)}; } - always_inline constexpr Vec2 topCenter() const { return {x + width / 2, y}; } + always_inline constexpr Vec2 topCenter() const { return {x + width / T(2), y}; } - always_inline constexpr Vec2 bottomCenter() const { return {x + width / 2, y + height}; } + always_inline constexpr Vec2 bottomCenter() const { return {x + width / T(2), y + height}; } - always_inline constexpr Vec2 startCenter() const { return {x, y + height / 2}; } + always_inline constexpr Vec2 startCenter() const { return {x, y + height / T(2)}; } - always_inline constexpr Vec2 endCenter() const { return {x + width, y + height / 2}; } + always_inline constexpr Vec2 endCenter() const { return {x + width, y + height / T(2)}; } always_inline constexpr Array, 4> vertices() const { return { @@ -183,20 +183,20 @@ union Rect { always_inline constexpr Rect fit(Rect r) const { auto scale = (r.size() / size().template cast()).min(); - Rect result{0, 0, static_cast(width * scale), static_cast(height * scale)}; + Rect result{T(0), T(0), static_cast(width * scale), static_cast(height * scale)}; result.xy = r.center() - result.center(); return result; } always_inline constexpr Rect cover(Rect r) const { f64 scale = (r.size() / size().template cast()).max(); - Rect result{0, 0, static_cast(width * scale), static_cast(height * scale)}; + Rect result{T(0), T(0), static_cast(width * scale), static_cast(height * scale)}; result.xy = r.center() - result.center(); return result; } always_inline constexpr Rect center(Rect r) const { - Rect result{0, 0, width, height}; + Rect result{T(0), T(0), width, height}; result.xy = center() - r.center(); return result; } @@ -343,7 +343,7 @@ template Rect const Rect::ZERO = {}; template -Rect const Rect::ONE = {1, 1}; +Rect const Rect::ONE = {T(1), T(1)}; template Rect const Rect::MAX = {Limits::MAX, Limits::MAX}; diff --git a/src/libs/karm-math/tests/test-fixed.cpp b/src/libs/karm-math/tests/test-fixed.cpp index a1723c47d..f0ec80032 100644 --- a/src/libs/karm-math/tests/test-fixed.cpp +++ b/src/libs/karm-math/tests/test-fixed.cpp @@ -71,4 +71,12 @@ test$("fixed-abs") { return Ok(); } +test$("frac+fixed") { + using P = i24f8; + + expectEq$(P(1) / P(2) + P(2), P(3) / P(2)); + + return Ok(); +} + } // namespace Karm::Math::Tests diff --git a/src/libs/karm-math/vec.h b/src/libs/karm-math/vec.h index 1796c2f17..eeba69c45 100644 --- a/src/libs/karm-math/vec.h +++ b/src/libs/karm-math/vec.h @@ -113,7 +113,7 @@ union Vec2 { constexpr T angleWith(Vec2 other) const { auto r = unit().dot(other.unit()); - auto sign = (x * other.y < y * other.x) ? -1.0 : 1.0; + auto sign = (x * other.y < y * other.x) ? T(-1.0) : T(1.0); return sign * acos(r); }