Skip to content

karm-math: Improve maths with fracs. #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/libs/karm-math/au.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ using RadiiAu = Math::Radii<Au>;
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};
}
29 changes: 26 additions & 3 deletions src/libs/karm-math/fixed.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <karm-base/checked.h>
#include <karm-io/fmt.h>

#include "funcs.h"

namespace Karm::Math {

template <typename T>
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 <Meta::SignedIntegral T, usize F>
Expand All @@ -205,8 +228,8 @@ constexpr _Frac<_Fixed<T, F>> _Fixed<T, F>::operator/(_Fixed<T, F> const& rhs) c
}

template <Meta::SignedIntegral T, usize F>
constexpr _Fixed<T, F> _Fixed<T, F>::operator/(_Frac<_Fixed<T, F>> const& rhs) const {
return fromRaw(saturatingDiv(_val, rhs._num) * rhs._deno);
constexpr _Frac<_Fixed<T, F>> _Fixed<T, F>::operator/(_Frac<_Fixed<T, F>> const& rhs) const {
return _Frac<_Fixed<T, F>>{fromRaw(_val) * rhs._deno, rhs._num};
}

using i24f8 = _Fixed<i32, 8>;
Expand Down
32 changes: 26 additions & 6 deletions src/libs/karm-math/funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <karm-base/clamp.h>
#include <karm-base/limits.h>
#include <karm-base/panic.h>

#include "const.h"

Expand All @@ -23,6 +24,16 @@ constexpr bool epsilonEq(T lhs, T rhs, T epsilon = Limits<T>::EPSILON) {
return abs(lhs - rhs) < epsilon;
}

template <Meta::Integral T>
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) {
Expand Down Expand Up @@ -200,17 +211,26 @@ constexpr T pow(T a, T b) {

template <typename T>
auto sqrt(T x) -> T {
if (x < 0.0)
return NAN;
if (x < T(0.0)) {
if constexpr (Meta::Float<T>)
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<T>) {
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;
}
Expand Down
10 changes: 5 additions & 5 deletions src/libs/karm-math/radii.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct Radii {
Radii reduceOverlap(Vec2<T> size) const {
auto res = *this;
auto scaleAll = [&](T factor) {
if (factor >= 1)
if (factor >= T(1))
return;
for (auto& radii : res.radii)
radii *= factor;
Expand All @@ -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;
}

Expand Down
22 changes: 11 additions & 11 deletions src/libs/karm-math/rect.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ union Rect {

always_inline static constexpr Rect<T> fromCenter(Vec2<T> center, Vec2<T> 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,
};
Expand Down Expand Up @@ -125,15 +125,15 @@ union Rect {

always_inline constexpr Vec2<T> bottomEnd() const { return {x + width, y + height}; }

always_inline constexpr Vec2<T> center() const { return {x + width / 2, y + height / 2}; }
always_inline constexpr Vec2<T> center() const { return {x + width / T(2), y + height / T(2)}; }

always_inline constexpr Vec2<T> topCenter() const { return {x + width / 2, y}; }
always_inline constexpr Vec2<T> topCenter() const { return {x + width / T(2), y}; }

always_inline constexpr Vec2<T> bottomCenter() const { return {x + width / 2, y + height}; }
always_inline constexpr Vec2<T> bottomCenter() const { return {x + width / T(2), y + height}; }

always_inline constexpr Vec2<T> startCenter() const { return {x, y + height / 2}; }
always_inline constexpr Vec2<T> startCenter() const { return {x, y + height / T(2)}; }

always_inline constexpr Vec2<T> endCenter() const { return {x + width, y + height / 2}; }
always_inline constexpr Vec2<T> endCenter() const { return {x + width, y + height / T(2)}; }

always_inline constexpr Array<Vec2<T>, 4> vertices() const {
return {
Expand Down Expand Up @@ -183,20 +183,20 @@ union Rect {

always_inline constexpr Rect fit(Rect<T> r) const {
auto scale = (r.size() / size().template cast<f64>()).min();
Rect result{0, 0, static_cast<T>(width * scale), static_cast<T>(height * scale)};
Rect result{T(0), T(0), static_cast<T>(width * scale), static_cast<T>(height * scale)};
result.xy = r.center() - result.center();
return result;
}

always_inline constexpr Rect cover(Rect<T> r) const {
f64 scale = (r.size() / size().template cast<f64>()).max();
Rect result{0, 0, static_cast<T>(width * scale), static_cast<T>(height * scale)};
Rect result{T(0), T(0), static_cast<T>(width * scale), static_cast<T>(height * scale)};
result.xy = r.center() - result.center();
return result;
}

always_inline constexpr Rect center(Rect<T> r) const {
Rect result{0, 0, width, height};
Rect result{T(0), T(0), width, height};
result.xy = center() - r.center();
return result;
}
Expand Down Expand Up @@ -343,7 +343,7 @@ template <typename T>
Rect<T> const Rect<T>::ZERO = {};

template <typename T>
Rect<T> const Rect<T>::ONE = {1, 1};
Rect<T> const Rect<T>::ONE = {T(1), T(1)};

template <typename T>
Rect<T> const Rect<T>::MAX = {Limits<T>::MAX, Limits<T>::MAX};
Expand Down
8 changes: 8 additions & 0 deletions src/libs/karm-math/tests/test-fixed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion src/libs/karm-math/vec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Loading