diff --git a/FindAzur.cmake b/FindAzur.cmake index 196e54f..861f65e 100644 --- a/FindAzur.cmake +++ b/FindAzur.cmake @@ -97,7 +97,8 @@ if(Azur_FOUND) set_target_properties(Azur::Azur PROPERTIES IMPORTED_LOCATION "${AZUR_LIB}" INTERFACE_INCLUDE_DIRECTORIES "${AZUR_INCLUDE}" - INTERFACE_COMPILE_OPTIONS "-DAZUR_PLATFORM=${AZUR_PLATFORM}") + INTERFACE_COMPILE_OPTIONS "-DAZUR_PLATFORM=${AZUR_PLATFORM}" + INTERFACE_LINK_LIBRARIES -lnum) if(AZUR_PLATFORM STREQUAL linux) pkg_check_modules(sdl2 REQUIRED sdl2 IMPORTED_TARGET) diff --git a/libnum/CMakeLists.txt b/libnum/CMakeLists.txt index a98d896..ec0fcaf 100644 --- a/libnum/CMakeLists.txt +++ b/libnum/CMakeLists.txt @@ -8,6 +8,7 @@ include(CTest) add_library(num STATIC + src/num.cpp src/str.cpp) target_include_directories(num PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/libnum/include/num/num.h b/libnum/include/num/num.h index cf45a74..9f08091 100644 --- a/libnum/include/num/num.h +++ b/libnum/include/num/num.h @@ -117,9 +117,15 @@ struct num8 v %= other.v; return *this; } + inline constexpr num8 ifloor() { + return 0; + } inline constexpr num8 floor() { return num8(0); } + inline constexpr num8 iceil() { + return v != 0; + } /* Warning: num8::ceil() always overflows! */ inline constexpr num8 ceil() { return num8(0); @@ -195,6 +201,9 @@ struct num16 /* num16 x num16 -> num32 multiplication This is efficiently implemented with a muls.w instruction. */ static constexpr num32 dmul(num16 const &x, num16 const &y); + /* num16 / num16 -> num16 division for positive numbers + This bypasses some sign tests, which saves a bit of time. */ + static constexpr num16 div_positive(num16 const &x, num16 const &y); /* Basic arithmetic */ @@ -218,11 +227,17 @@ struct num16 v %= other.v; return *this; } + inline constexpr int ifloor() { + return v >> 8; + } inline constexpr num16 floor() { num16 x; x.v = v & 0xff00; return x; } + inline constexpr int iceil() { + return (v + 0xff) >> 8; + } inline constexpr num16 ceil() { num16 x; x.v = ((v - 1) | 0xff) + 1; @@ -330,11 +345,17 @@ struct num32 v %= other.v; return *this; } + inline constexpr int ifloor() { + return v >> 16; + } inline constexpr num32 floor() { num32 x; x.v = v & 0xffff0000; return x; } + inline constexpr int iceil() { + return (v + 0xffff) >> 16; + } inline constexpr num32 ceil() { num32 x; x.v = ((v - 1) | 0xffff) + 1; @@ -345,6 +366,7 @@ struct num32 x.v = v & 0xffff; return x; } + num32 sqrt() const; /* Comparisons with int */ @@ -447,11 +469,17 @@ struct num64 v %= other.v; return *this; } + inline constexpr int ifloor() { + return v >> 32; + } inline constexpr num64 floor() { num64 x; x.v = v & 0xffffffff00000000ull; return x; } + inline constexpr int iceil() { + return (v >> 32) + ((uint32_t)v != 0); + } inline constexpr num64 ceil() { num64 x; x.v = ((v - 1) | 0xffffffffull) + 1; @@ -569,6 +597,26 @@ inline constexpr T operator-(T const &op) { return T(0) - op; } +/* Internal minima, maxima and clamp */ + +template requires(is_num) +inline constexpr T min(T const &left, T const &right) +{ + return (left < right) ? left : right; +} + +template requires(is_num) +inline constexpr T max(T const &left, T const &right) +{ + return (left > right) ? left : right; +} + +template requires(is_num) +inline constexpr T clamp(T const &val, T const &lower, T const &upper) +{ + return max(lower, min(val, upper)); +} + /* Other specific operations */ inline constexpr num32 num16::dmul(num16 const &x, num16 const &y) @@ -578,6 +626,13 @@ inline constexpr num32 num16::dmul(num16 const &x, num16 const &y) return n; } +inline constexpr num16 num16::div_positive(num16 const &x, num16 const &y) +{ + num16 r; + r.v = ((uint32_t)(uint16_t)x.v << 8) / (uint16_t)y.v; + return r; +} + inline constexpr num64 num32::dmul(num32 const &x, num32 const &y) { num64 n; @@ -585,4 +640,12 @@ inline constexpr num64 num32::dmul(num32 const &x, num32 const &y) return n; } +/* Floor modulo. We provide an optimized version for constants, which optimizes + away the main condition. */ +template requires(is_num) +inline constexpr T modf(T const &x, T const &y) { + T r = x % y; + return (r.v && (r.v ^ y.v) < 0) ? r + y : r; +} + } /* namespace libnum */ diff --git a/libnum/include/num/vec.h b/libnum/include/num/vec.h index ffd375e..b95afe5 100644 --- a/libnum/include/num/vec.h +++ b/libnum/include/num/vec.h @@ -189,6 +189,10 @@ inline constexpr vec operator*(T const &lhs, vec rhs) { rhs[i] *= lhs; return rhs; } +template +inline constexpr vec operator/(vec lhs, T const &rhs) { + return lhs /= rhs; +} /* Comparisons */ diff --git a/libnum/src/num.cpp b/libnum/src/num.cpp new file mode 100644 index 0000000..db86219 --- /dev/null +++ b/libnum/src/num.cpp @@ -0,0 +1,21 @@ +#include +using namespace libnum; + +/* Integer square root (rather slow) */ +static int64_t sqrtll(int64_t n) +{ + if(n < 4) + return (n > 0); + + int64_t low_bound = sqrtll(n / 4) * 2; + int64_t high_bound = low_bound + 1; + + return (high_bound * high_bound <= n) ? high_bound : low_bound; +} + +num32 num32::sqrt() const +{ + num32 r; + r.v = sqrtll((int64_t)v << 16); + return r; +} diff --git a/libnum/test/isel.py b/libnum/test/isel.py index 9ece295..ad406f8 100644 --- a/libnum/test/isel.py +++ b/libnum/test/isel.py @@ -306,7 +306,7 @@ class ExprParser: return decorate def binaryOpsRight(ctor, ops): - return binaryOpsRight(ctor, ops, rassoc=True) + return binaryOps(ctor, ops, rassoc=True) def unaryOps(ctor, ops, assoc=True): def decorate(f):