diff --git a/copying.md b/copying.md index dd71a8dc82..862f18bb39 100644 --- a/copying.md +++ b/copying.md @@ -163,6 +163,7 @@ _the openage authors_ are: | Ngô Xuân Minh | | xminh dawt ngo dawt 00 à gmail dawt com | | Haytham Tang | haytham918 | yunxuant à umich dawt edu | | Ana Trias-Labellarte | anatriaslabella | ana dawt triaslabella à ufl dawt edu | +| Eelco Empting | Eeelco | me à eelco dawt de | If you're a first-time committer, add yourself to the above list. This is not just for legal reasons, but also to keep an overview of all those nicknames. diff --git a/libopenage/testing/testing.h b/libopenage/testing/testing.h index 50e03338e0..83f0efaab9 100644 --- a/libopenage/testing/testing.h +++ b/libopenage/testing/testing.h @@ -1,4 +1,4 @@ -// Copyright 2014-2024 the openage authors. See copying.md for legal info. +// Copyright 2014-2025 the openage authors. See copying.md for legal info. #pragma once @@ -51,7 +51,9 @@ bool fail(const log::message &msg); try { \ auto &&test_result_left = (left); \ if (test_result_left != (right)) { \ - TESTFAILMSG("unexpected value: " << (test_result_left)); \ + TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " \ + << test_result_left << " and " \ + << (right) << " to be equal"); \ } \ } \ catch (::openage::testing::TestError & e) { \ @@ -63,6 +65,28 @@ bool fail(const log::message &msg); } \ while (0) +/** + * Asserts that the left expression does not equal the right expression, + * and that no exception is thrown. + */ +#define TESTNOTEQUALS(left, right) \ + do { \ + try { \ + auto &&test_result_left = (left); \ + if (test_result_left == (right)) { \ + TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " \ + << test_result_left << " and " \ + << (right) << " to be NOT equal"); \ + } \ + } \ + catch (::openage::testing::TestError & e) { \ + throw; \ + } \ + catch (::openage::error::Error & e) { \ + TESTFAILMSG("unexpected exception: " << e); \ + } \ + } \ + while (0) /** * Asserts that the left expression equals the right expression, @@ -72,8 +96,9 @@ bool fail(const log::message &msg); do { \ try { \ auto &&test_result_left = (left); \ - if ((test_result_left < (right - epsilon)) or (test_result_left > (right + epsilon))) { \ - TESTFAILMSG("unexpected value: " << (test_result_left)); \ + auto &&test_result_right = (right); \ + if ((test_result_left < (test_result_right - epsilon)) or (test_result_left > (test_result_right + epsilon))) { \ + TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": Expected " << (test_result_left) << " and " << (test_result_right) << " to be equal"); \ } \ } \ catch (::openage::testing::TestError & e) { \ @@ -99,7 +124,7 @@ bool fail(const log::message &msg); expr_has_thrown = true; \ } \ if (not expr_has_thrown) { \ - TESTFAILMSG("no exception"); \ + TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": no exception"); \ } \ } \ while (0) @@ -114,7 +139,7 @@ bool fail(const log::message &msg); expression; \ } \ catch (::openage::error::Error & e) { \ - TESTFAILMSG("unexpected exception"); \ + TESTFAILMSG(__FILE__ << ":" << __LINE__ << ": unexpected exception"); \ } \ } \ while (0) diff --git a/libopenage/util/fixed_point.h b/libopenage/util/fixed_point.h index e9f86ce0ef..2d6a7eb084 100644 --- a/libopenage/util/fixed_point.h +++ b/libopenage/util/fixed_point.h @@ -85,14 +85,16 @@ constexpr static * If you change this class, remember to update the gdb pretty printers * in etc/gdb_pretty/printers.py. */ -template +template class FixedPoint { public: using raw_type = int_type; - using this_type = FixedPoint; + using this_type = FixedPoint; using unsigned_int_type = typename std::make_unsigned::type; + using unsigned_intermediate_type = typename std::make_unsigned::type; + using same_type_but_unsigned = FixedPoint; + fractional_bits, typename FixedPoint::unsigned_intermediate_type>; private: // Helper function to create the scaling factors that are used below. @@ -264,14 +266,14 @@ class FixedPoint { /** * Factory function to get a fixed-point number from a fixed-point number of different type. */ - template other_fractional_bits)>::type * = nullptr> - static constexpr FixedPoint from_fixedpoint(const FixedPoint &other) { + template other_fractional_bits)>::type * = nullptr> + static constexpr FixedPoint from_fixedpoint(const FixedPoint &other) { return FixedPoint::from_raw_value( safe_shift(static_cast(other.get_raw_value()))); } - template ::type * = nullptr> - static constexpr FixedPoint from_fixedpoint(const FixedPoint &other) { + template ::type * = nullptr> + static constexpr FixedPoint from_fixedpoint(const FixedPoint &other) { return FixedPoint::from_raw_value( static_cast(other.get_raw_value() / safe_shiftleft(1))); } @@ -380,14 +382,14 @@ class FixedPoint { return FixedPoint::this_type::from_raw_value(-this->raw_value); } - template - constexpr double hypot(const FixedPoint rhs) { + template + constexpr double hypot(const FixedPoint rhs) { return std::hypot(this->to_double(), rhs.to_double()); } - template - constexpr FixedPoint hypotfp(const FixedPoint rhs) { - return FixedPoint(this->hypot(rhs)); + template + constexpr FixedPoint hypotfp(const FixedPoint rhs) { + return FixedPoint(this->hypot(rhs)); } // Basic operators @@ -471,42 +473,42 @@ class FixedPoint { /** * FixedPoint + FixedPoint */ -template -constexpr FixedPoint operator+(const FixedPoint &lhs, const FixedPoint &rhs) { - return FixedPoint::from_raw_value(lhs.get_raw_value() + rhs.get_raw_value()); +template +constexpr FixedPoint operator+(const FixedPoint &lhs, const FixedPoint &rhs) { + return FixedPoint::from_raw_value(lhs.get_raw_value() + rhs.get_raw_value()); } /** * FixedPoint + double */ -template -constexpr FixedPoint operator+(const FixedPoint &lhs, const double &rhs) { - return FixedPoint{lhs} + FixedPoint::from_double(rhs); +template +constexpr FixedPoint operator+(const FixedPoint &lhs, const double &rhs) { + return FixedPoint{lhs} + FixedPoint::from_double(rhs); } /** * FixedPoint - FixedPoint */ -template -constexpr FixedPoint operator-(const FixedPoint &lhs, const FixedPoint &rhs) { - return FixedPoint::from_raw_value(lhs.get_raw_value() - rhs.get_raw_value()); +template +constexpr FixedPoint operator-(const FixedPoint &lhs, const FixedPoint &rhs) { + return FixedPoint::from_raw_value(lhs.get_raw_value() - rhs.get_raw_value()); } /** * FixedPoint - double */ -template -constexpr FixedPoint operator-(const FixedPoint &lhs, const double &rhs) { - return FixedPoint{lhs} - FixedPoint::from_double(rhs); +template +constexpr FixedPoint operator-(const FixedPoint &lhs, const double &rhs) { + return FixedPoint{lhs} - FixedPoint::from_double(rhs); } /** * FixedPoint * N */ -template -typename std::enable_if::value, FixedPoint>::type constexpr operator*(const FixedPoint lhs, const N &rhs) { - return FixedPoint::from_raw_value(lhs.get_raw_value() * rhs); +template +typename std::enable_if::value, FixedPoint>::type constexpr operator*(const FixedPoint lhs, const N &rhs) { + return FixedPoint::from_raw_value(lhs.get_raw_value() * rhs); } /* @@ -523,40 +525,41 @@ typename std::enable_if::value, FixedPoint>::type co * => a * a will overflow because: * a.rawvalue == 2^(16+16) == 2^32 * -> a.rawvalue * a.rawvalue == 2^64 => pwnt + * + * Use a larger intermediate type to prevent overflow */ -// template -// constexpr FixedPoint operator*(const FixedPoint lhs, const FixedPoint rhs) { -// I ret = 0; -// if (not __builtin_mul_overflow(lhs.get_raw_value(), rhs.get_raw_value(), &ret)) { -// throw std::overflow_error("FixedPoint multiplication overflow"); -// } +template +constexpr FixedPoint operator*(const FixedPoint lhs, const FixedPoint rhs) { + Inter ret = static_cast(lhs.get_raw_value()) * static_cast(rhs.get_raw_value()); + ret >>= F; -// return FixedPoint::from_raw_value(ret); -// } + return FixedPoint::from_raw_value(static_cast(ret)); +} /** * FixedPoint / FixedPoint */ -template -constexpr FixedPoint operator/(const FixedPoint lhs, const FixedPoint rhs) { - return FixedPoint::from_raw_value(div(lhs.get_raw_value(), rhs.get_raw_value()) << F); +template +constexpr FixedPoint operator/(const FixedPoint lhs, const FixedPoint rhs) { + Inter ret = div((static_cast(lhs.get_raw_value()) << F), static_cast(rhs.get_raw_value())); + return FixedPoint::from_raw_value(static_cast(ret)); } /** * FixedPoint / N */ -template -constexpr FixedPoint operator/(const FixedPoint lhs, const N &rhs) { - return FixedPoint::from_raw_value(div(lhs.get_raw_value(), static_cast(rhs))); +template +constexpr FixedPoint operator/(const FixedPoint lhs, const N &rhs) { + return FixedPoint::from_raw_value(div(lhs.get_raw_value(), static_cast(rhs))); } /** * FixedPoint % FixedPoint (modulo) */ -template -constexpr FixedPoint operator%(const FixedPoint lhs, const FixedPoint rhs) { +template +constexpr FixedPoint operator%(const FixedPoint lhs, const FixedPoint rhs) { auto div = (lhs / rhs); auto n = div.to_int(); return lhs - (rhs * n); @@ -569,71 +572,71 @@ constexpr FixedPoint operator%(const FixedPoint lhs, const FixedPoin // std function overloads namespace std { -template -constexpr double sqrt(openage::util::FixedPoint n) { +template +constexpr double sqrt(openage::util::FixedPoint n) { return n.sqrt(); } -template -constexpr double atan2(openage::util::FixedPoint x, openage::util::FixedPoint y) { +template +constexpr double atan2(openage::util::FixedPoint x, openage::util::FixedPoint y) { return x.atan2(y); } -template -constexpr double sin(openage::util::FixedPoint n) { +template +constexpr double sin(openage::util::FixedPoint n) { return n.sin(); } -template -constexpr double cos(openage::util::FixedPoint n) { +template +constexpr double cos(openage::util::FixedPoint n) { return n.cos(); } -template -constexpr double tan(openage::util::FixedPoint n) { +template +constexpr double tan(openage::util::FixedPoint n) { return n.tan(); } -template -constexpr openage::util::FixedPoint min(openage::util::FixedPoint x, openage::util::FixedPoint y) { - return openage::util::FixedPoint::from_raw_value( +template +constexpr openage::util::FixedPoint min(openage::util::FixedPoint x, openage::util::FixedPoint y) { + return openage::util::FixedPoint::from_raw_value( std::min(x.get_raw_value(), y.get_raw_value())); } -template -constexpr openage::util::FixedPoint max(openage::util::FixedPoint x, openage::util::FixedPoint y) { - return openage::util::FixedPoint::from_raw_value( +template +constexpr openage::util::FixedPoint max(openage::util::FixedPoint x, openage::util::FixedPoint y) { + return openage::util::FixedPoint::from_raw_value( std::max(x.get_raw_value(), y.get_raw_value())); } -template -constexpr openage::util::FixedPoint abs(openage::util::FixedPoint n) { - return openage::util::FixedPoint::from_raw_value( +template +constexpr openage::util::FixedPoint abs(openage::util::FixedPoint n) { + return openage::util::FixedPoint::from_raw_value( std::abs(n.get_raw_value())); } -template -constexpr double hypot(openage::util::FixedPoint x, openage::util::FixedPoint y) { +template +constexpr double hypot(openage::util::FixedPoint x, openage::util::FixedPoint y) { return x.hypot(y); } -template -struct hash> { - constexpr size_t operator()(const openage::util::FixedPoint &n) const { +template +struct hash> { + constexpr size_t operator()(const openage::util::FixedPoint &n) const { return std::hash{}(n.raw_value); } }; -template -struct numeric_limits> { - constexpr static openage::util::FixedPoint min() { - return openage::util::FixedPoint::min_value(); +template +struct numeric_limits> { + constexpr static openage::util::FixedPoint min() { + return openage::util::FixedPoint::min_value(); } - constexpr static openage::util::FixedPoint max() { - return openage::util::FixedPoint::max_value(); + constexpr static openage::util::FixedPoint max() { + return openage::util::FixedPoint::max_value(); } }; diff --git a/libopenage/util/fixed_point_test.cpp b/libopenage/util/fixed_point_test.cpp index 7a7fb2bc0c..21fd788259 100644 --- a/libopenage/util/fixed_point_test.cpp +++ b/libopenage/util/fixed_point_test.cpp @@ -1,4 +1,4 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. +// Copyright 2016-2025 the openage authors. See copying.md for legal info. #include "fixed_point.h" @@ -122,6 +122,40 @@ void fixed_point() { TESTEQUALS_FLOAT(TestTypeShort::e().to_double(), math::E, 1e-3); TESTEQUALS_FLOAT(TestTypeShort::pi().to_double(), math::PI, 1e-3); + { + using S = FixedPoint; + using T = FixedPoint; + + auto a = S::from_int(16U); + TESTNOTEQUALS((a*a).to_int(), 256U); + + auto b = T::from_int(16U); + TESTEQUALS((b*b).to_int(), 256U); + + auto c = T::from_int(17U); + TESTEQUALS((c*c).to_int(), 289U); + } + { + using S = FixedPoint; + auto a = S::from_int(256); + auto b = S::from_int(8); + TESTNOTEQUALS((a/b).to_int(), 32); + + + using T = FixedPoint; + auto c = T::from_int(256); + auto d = T::from_int(8); + TESTEQUALS((c/d).to_int(), 32); + } + { + using T = FixedPoint; + auto a = T::from_double(4.75); + auto b = T::from_double(3.5); + auto c = -a; + TESTEQUALS_FLOAT((a/b).to_double(), 4.75/3.5, 0.1); + TESTEQUALS_FLOAT((c/b).to_double(), -4.75/3.5, 0.1); + } + } }}} // openage::util::tests