From 26d215be0a9f07a64e3f02018fede29b703b669b Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Thu, 4 Apr 2024 18:23:34 -0400 Subject: [PATCH] finish fixed point --- CMakeLists.txt | 2 +- include/blt/math/fixed_point.h | 210 ++++++++++++++++++++++++--------- tests/src/math_tests.cpp | 56 +++++++-- 3 files changed, 200 insertions(+), 68 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfdbc94..20c84a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.5) include(cmake/color.cmake) -set(BLT_VERSION 0.16.4) +set(BLT_VERSION 0.16.5) set(BLT_TEST_VERSION 0.0.1) set(BLT_TARGET BLT) diff --git a/include/blt/math/fixed_point.h b/include/blt/math/fixed_point.h index ee93fa0..15fc682 100644 --- a/include/blt/math/fixed_point.h +++ b/include/blt/math/fixed_point.h @@ -20,140 +20,232 @@ #define BLT_FIXED_POINT_H #include -#include +//#include -#define BLT_DEBUG_NO_INLINE BLT_ATTRIB_NO_INLINE +//#define BLT_DEBUG_NO_INLINE BLT_ATTRIB_NO_INLINE +#define BLT_DEBUG_NO_INLINE namespace blt { struct fp64 { private: - u64 v = 0; + i64 v = 0; - fp64() = default; - - explicit fp64(u64 v): v(v) - {} - + constexpr fp64() = default; public: - static fp64 from_u64(u64 ui) + constexpr explicit fp64(u64 ui): v(from_u64(ui)) + {} + + constexpr explicit fp64(i64 si): v(from_i64(si)) + {} + + constexpr explicit fp64(u32 ui): v(from_u32(ui)) + {} + + constexpr explicit fp64(i32 si): v(from_i32(si)) + {} + + constexpr explicit fp64(f32 f): v(from_f32(f)) + {} + + constexpr explicit fp64(f64 d): v(from_f64(d)) + {} + + constexpr static inline fp64 from_raw(i64 i) + { + fp64 r; + r.v = i; + return r; + } + + constexpr static inline fp64 from_raw_u64(u64 u) + { + fp64 r; + r.v = static_cast(u); + return r; + } + + constexpr static inline fp64 from_u64(u64 ui) + { + return from_i64(static_cast(ui)); + } + + constexpr static inline fp64 from_i64(i64 si) + { + return from_raw(si << 32); + } + + constexpr static inline fp64 from_u32(u32 ui) + { + return from_i64(static_cast(ui)); + } + + constexpr static inline fp64 from_i32(i32 si) + { + return from_i64(static_cast(si)); + } + + constexpr static inline fp64 from_f64(f64 d) { fp64 fp; - fp.v = ui << 32; + fp.v = static_cast(d * (1ul << 32ul)); return fp; } - static fp64 from_i64(i64 si) - { - u64 ui = static_cast(si); - fp64 fp; - fp.v = ui << 32; - return fp; - } - - static fp64 from_f64(f64 d) - { - fp64 fp; - fp.v = static_cast(d * (1ul << 32ul)); - return fp; - } - - static fp64 from_f32(f32 f) + constexpr static inline fp64 from_f32(f32 f) { return from_f64(static_cast(f)); } - BLT_DEBUG_NO_INLINE friend fp64 operator+(fp64 left, fp64 right) + BLT_DEBUG_NO_INLINE constexpr friend inline fp64 operator+(fp64 left, fp64 right) { - return fp64(left.v + right.v); + return from_raw(left.v + right.v); } - BLT_DEBUG_NO_INLINE friend fp64 operator-(fp64 left, fp64 right) + BLT_DEBUG_NO_INLINE constexpr friend inline fp64 operator-(fp64 left, fp64 right) { - return fp64(left.v - right.v); + return from_raw(left.v - right.v); } - BLT_DEBUG_NO_INLINE friend fp64 operator*(fp64 left, fp64 right) + BLT_DEBUG_NO_INLINE constexpr friend inline fp64 operator*(fp64 left, fp64 right) { - auto lhs = static_cast(left.v); - auto rhs = static_cast(right.v); - return fp64(static_cast((lhs * rhs) >> 32)); + auto lhs = static_cast<__int128>(left.v); + auto rhs = static_cast<__int128>(right.v); + return from_raw(static_cast((lhs * rhs) >> 32)); } - BLT_DEBUG_NO_INLINE friend fp64 operator/(fp64 left, fp64 right) + BLT_DEBUG_NO_INLINE constexpr friend inline fp64 operator/(fp64 left, fp64 right) { - auto lhs = static_cast(left.v) << 32; - auto rhs = static_cast(right.v); - - return fp64(static_cast(lhs / rhs)); + auto lhs = static_cast<__int128>(left.v) << 32; + return from_raw(static_cast(lhs / right.v)); } - [[nodiscard]] inline u64 as_u64() const + BLT_DEBUG_NO_INLINE constexpr inline fp64& operator+=(fp64 add) + { + v += add.v; + return *this; + } + + BLT_DEBUG_NO_INLINE constexpr inline fp64& operator-=(fp64 sub) + { + v -= sub.v; + return *this; + } + + BLT_DEBUG_NO_INLINE constexpr inline fp64& operator*=(fp64 mul) + { + auto lhs = static_cast<__int128>(v); + auto rhs = static_cast<__int128>(mul.v); + v = static_cast((lhs * rhs) >> 32); + return *this; + } + + BLT_DEBUG_NO_INLINE constexpr inline fp64& operator/=(fp64 div) + { + auto lhs = static_cast<__int128>(v) << 32; + v = static_cast(lhs / div.v); + return *this; + } + + [[nodiscard]] constexpr inline u64 as_u64() const + { + return static_cast(v) >> 32; + } + + [[nodiscard]] constexpr inline i64 as_i64() const { return v >> 32; } - [[nodiscard]] inline i64 as_i64() const + [[nodiscard]] constexpr inline u32 as_u32() const { - return static_cast(as_u64()); + return static_cast(v >> 32); } - [[nodiscard]] inline u32 as_u32() const + [[nodiscard]] constexpr inline i32 as_i32() const { - return static_cast(as_u64()); + return static_cast(v >> 32); } - [[nodiscard]] inline i32 as_i32() const - { - return static_cast(as_u64()); - } - - [[nodiscard]] inline f64 as_f64() const + [[nodiscard]] constexpr inline f64 as_f64() const { return static_cast(v) / static_cast(1ul << 32ul); } - [[nodiscard]] inline f32 as_f32() const + [[nodiscard]] constexpr inline f32 as_f32() const { - return static_cast(as_f64()); + return static_cast(v) / static_cast(1ul << 32ul); } - inline explicit operator u64() const + constexpr inline explicit operator u64() const { return as_u64(); } - inline explicit operator i64() const + constexpr inline explicit operator i64() const { return as_i64(); } - inline explicit operator u32() const + constexpr inline explicit operator u32() const { return as_u32(); } - inline explicit operator i32() const + constexpr inline explicit operator i32() const { return as_i32(); } - inline explicit operator f32() const + constexpr inline explicit operator f32() const { return as_f32(); }; - inline explicit operator f64() const + constexpr inline explicit operator f64() const { return as_f64(); } - [[nodiscard]] u64 raw() const + [[nodiscard]] constexpr u64 raw() const { return v; } }; + + // max unsigned integer value + static constexpr const inline fp64 FP64_UMAX = fp64::from_raw_u64(0xFFFFFFFF00000000); + // min unsigned integer value + static constexpr const inline fp64 FP64_UMIN = fp64::from_raw_u64(0x0000000000000000); + // max signed integer value + static constexpr const inline fp64 FP64_IMAX = fp64::from_raw_u64(0x7FFFFFFF00000000); + // min signed integer value + static constexpr const inline fp64 FP64_IMIN = fp64::from_raw_u64(0x8000000000000000); + // max value storable including floating point + static constexpr const inline fp64 FP64_FMAX = fp64::from_raw_u64(0x7FFFFFFFFFFFFFFF); + // min float point number + static constexpr const inline fp64 FP64_FMIN = fp64::from_raw_u64(0x8000000000000000); + // smallest decimal number + static constexpr const inline fp64 FP64_EPSILON = fp64::from_raw_u64(0x0000000000000001); + // pi + static constexpr const inline fp64 FP64_PI = fp64::from_f64(3.14159265358979323846); + // pi / 2 + static constexpr const inline fp64 FP64_PI_2 = fp64::from_f64(1.57079632679489661923); + // pi / 4 + static constexpr const inline fp64 FP64_PI_4 = fp64::from_f64(0.78539816339744830962); + // 1 / pi + static constexpr const inline fp64 FP64_1_PI = fp64::from_f64(0.31830988618379067154); + // 2 / pi + static constexpr const inline fp64 FP64_2_PI = fp64::from_f64(0.63661977236758134308); + // sqrt(2) + static constexpr const inline fp64 FP64_SQRT2 = fp64::from_f64(1.41421356237309504880); + // 1 / sqrt(2) + static constexpr const inline fp64 FP64_1_SQRT2 = fp64::from_f64(0.70710678118654752440); + // e + static constexpr const inline fp64 FP64_E = fp64::from_f64(2.7182818284590452354f); + // log2(e) + static constexpr const inline fp64 FP64_LOG2E = fp64::from_f64(1.4426950408889634074f); } #endif //BLT_FIXED_POINT_H diff --git a/tests/src/math_tests.cpp b/tests/src/math_tests.cpp index 8166255..428fda4 100644 --- a/tests/src/math_tests.cpp +++ b/tests/src/math_tests.cpp @@ -19,31 +19,71 @@ #include #include #include +#include #include #include +#include +#include using vec3fp = blt::vec; namespace blt::test { + void print(fp64 v, const std::string& name = "") + { + std::cout << name << " [" << v.raw() << ':' << std::hex << v.raw() << std::dec << "]\tu64(" << v.as_u64() << ")\ti64(" << v.as_i64() + << ")\tu32(" << v.as_u32() << ")\ti32(" << v.as_i32() << ")\tf32(" + << std::setprecision(std::numeric_limits::digits10 + 1) + << std::setw(16) << std::fixed << v.as_f32() << ")\tf64(" << v.as_f64() << ")\n"; + } + void fixed_point() { //vec3fp hello = {fp64::from_f64(32.023), fp64::from_f64(422.34023), fp64::from_f64(321.023)}; + print(FP64_UMAX, "umax"); + print(FP64_UMIN, "umin"); + print(FP64_IMAX, "imax"); + print(FP64_IMIN, "imin"); + print(FP64_FMAX, "fmax"); + print(FP64_FMIN, "fmin"); + print(FP64_EPSILON, "epis"); + print(FP64_PI, "pi "); + print(FP64_PI_2, "pi2 "); + print(FP64_PI_4, "pi4 "); + print(FP64_1_PI, "1/pi"); + print(FP64_2_PI, "1/p2"); + print(FP64_SQRT2, "sqr2"); + print(FP64_1_SQRT2, "isq2"); + print(FP64_E, "e "); + print(FP64_LOG2E, "logE"); + fp64 uv = fp64::from_u64(32); fp64 iv = fp64::from_i64(16); fp64 fv = fp64::from_f32(53.4234234); fp64 pi = fp64::from_f64(M_PI); - std::cout << "[" << static_cast(uv) << "]: " << uv.as_i64() << " : " << uv.as_u64() << " : " << uv.as_f64() << std::endl; - std::cout << "[" << static_cast(iv) << "]: " << iv.as_i64() << " : " << iv.as_u64() << " : " << iv.as_f64() << std::endl; - std::cout << "[" << static_cast(fv) << "]: " << fv.as_i64() << " : " << fv.as_u64() << " : " << fv.as_f64() << std::endl; - std::cout << "[" << static_cast(pi) << "]: " << pi.as_i64() << " : " << pi.as_u64() << " : " << pi.as_f64() << std::endl; + print(uv * iv, "32 * 16"); + print(uv / iv, "32 / 16"); + print(fv / pi, "53.4234234 / pi"); - std::cout << (uv * iv).as_i64() << std::endl; - std::cout << (uv * iv).as_u64() << std::endl; - std::cout << (uv / iv).as_i64() << std::endl; - std::cout << (uv / iv).as_u64() << std::endl; + print(uv + iv, "32 + 16"); + print(uv - iv, "32 - 16"); + + print(fp64::from_f32(32.43242), "32.43242"); + print(fp64::from_f64(634.2349932493423), "634.2349932493423"); + print(fp64::from_u32(3194967295), "3194967295"); + print(fp64::from_i32(-1194967295), "-1194967295"); + print(fp64::from_i64(-13194967295), "-13194967295"); + print(fp64::from_u64(66294967295), "66294967295"); + + uv *= fp64::from_i32(-32); + + print(uv); + + uv /= fp64::from_i32(-16); + + print(uv); } } \ No newline at end of file