From e5a7ddfa0aeb8f62e2b53f111122c1c51c03dabc Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 19 Feb 2024 20:36:19 +0000 Subject: Fixed point rounding functions and sources cleanup --- src/openvic-simulation/testing/Requirement.cpp | 8 +++ src/openvic-simulation/testing/Requirement.hpp | 12 ++-- src/openvic-simulation/testing/TestScript.cpp | 2 + src/openvic-simulation/testing/TestScript.hpp | 4 +- .../testing/test_scripts/A_001_file_tests.cpp | 3 +- .../testing/test_scripts/A_002_economy_tests.cpp | 3 +- .../test_scripts/A_003_military_unit_tests.cpp | 3 +- .../test_scripts/A_004_networking_tests.cpp | 3 +- .../testing/test_scripts/A_005_nation_tests.cpp | 3 +- .../testing/test_scripts/A_006_politics_tests.cpp | 3 +- .../types/fixed_point/FixedPoint.hpp | 73 +++++++++++++++++----- .../types/fixed_point/FixedPointLUT.hpp | 25 -------- .../types/fixed_point/FixedPointLUT_sin.hpp | 4 +- .../types/fixed_point/FixedPointMath.hpp | 11 ---- .../fixed_point/lut_generator/lut_generator.py | 4 +- src/openvic-simulation/utility/Getters.hpp | 2 +- 16 files changed, 88 insertions(+), 75 deletions(-) delete mode 100644 src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp delete mode 100644 src/openvic-simulation/types/fixed_point/FixedPointMath.hpp (limited to 'src') diff --git a/src/openvic-simulation/testing/Requirement.cpp b/src/openvic-simulation/testing/Requirement.cpp index e7d03e5..eb48f5b 100644 --- a/src/openvic-simulation/testing/Requirement.cpp +++ b/src/openvic-simulation/testing/Requirement.cpp @@ -6,3 +6,11 @@ void Requirement::set_pass(bool in_pass) { pass = in_pass; set_tested(true); // Ever setting a pass condition implies it has been tested } + +void Requirement::set_target_value(std::string_view new_target_value) { + target_value = new_target_value; +} + +void Requirement::set_actual_value(std::string_view new_actual_value) { + actual_value = new_actual_value; +} diff --git a/src/openvic-simulation/testing/Requirement.hpp b/src/openvic-simulation/testing/Requirement.hpp index e91fa79..85a1573 100644 --- a/src/openvic-simulation/testing/Requirement.hpp +++ b/src/openvic-simulation/testing/Requirement.hpp @@ -7,15 +7,15 @@ namespace OpenVic { class Requirement { // Loaded during construction - std::string PROPERTY_RW(id); - std::string PROPERTY_RW(text); - std::string PROPERTY_RW(acceptance_criteria); + std::string PROPERTY(id); + std::string PROPERTY(text); + std::string PROPERTY(acceptance_criteria); bool PROPERTY(pass); bool PROPERTY_RW(tested); // Initialised and used during script execution - std::string PROPERTY_RW(target_value); - std::string PROPERTY_RW(actual_value); + std::string PROPERTY(target_value); + std::string PROPERTY(actual_value); public: Requirement(std::string in_id, std::string in_text, std::string in_acceptance_criteria) { @@ -27,5 +27,7 @@ namespace OpenVic { } void set_pass(bool in_pass); + void set_target_value(std::string_view new_target_value); + void set_actual_value(std::string_view new_actual_value); }; } diff --git a/src/openvic-simulation/testing/TestScript.cpp b/src/openvic-simulation/testing/TestScript.cpp index ab0bfb9..13858fb 100644 --- a/src/openvic-simulation/testing/TestScript.cpp +++ b/src/openvic-simulation/testing/TestScript.cpp @@ -2,6 +2,8 @@ using namespace OpenVic; +TestScript::TestScript(std::string_view new_script_name) : script_name { new_script_name } {} + // Getters std::vector TestScript::get_requirements() { return requirements; diff --git a/src/openvic-simulation/testing/TestScript.hpp b/src/openvic-simulation/testing/TestScript.hpp index b41246e..fdf23a5 100644 --- a/src/openvic-simulation/testing/TestScript.hpp +++ b/src/openvic-simulation/testing/TestScript.hpp @@ -10,9 +10,11 @@ namespace OpenVic { std::vector requirements = std::vector(); GameManager* PROPERTY_RW(game_manager); - std::string PROPERTY_RW(script_name); + std::string PROPERTY(script_name); public: + TestScript(std::string_view new_script_name); + // expects an overriden method that performs arbitrary code execution // so that each script uniquely performs tests // for both requirement adding to script and to execute code diff --git a/src/openvic-simulation/testing/test_scripts/A_001_file_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_001_file_tests.cpp index e24d44c..213da76 100644 --- a/src/openvic-simulation/testing/test_scripts/A_001_file_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_001_file_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_001_file_tests : public TestScript { public: - A_001_file_tests() { - set_script_name("A_001_file_tests"); + A_001_file_tests() : TestScript { "A_001_file_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp index 4bff710..e811144 100644 --- a/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_002_economy_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_002_economy_tests : public TestScript { public: - A_002_economy_tests() { - set_script_name("A_002_economy_tests"); + A_002_economy_tests() : TestScript { "A_002_economy_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/testing/test_scripts/A_003_military_unit_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_003_military_unit_tests.cpp index cf572d0..b61abb4 100644 --- a/src/openvic-simulation/testing/test_scripts/A_003_military_unit_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_003_military_unit_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_003_military_unit_tests : public TestScript { public: - A_003_military_unit_tests() { - set_script_name("A_003_military_unit_tests"); + A_003_military_unit_tests() : TestScript { "A_003_military_unit_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/testing/test_scripts/A_004_networking_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_004_networking_tests.cpp index 0e05540..984a3c2 100644 --- a/src/openvic-simulation/testing/test_scripts/A_004_networking_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_004_networking_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_004_networking_tests : public TestScript { public: - A_004_networking_tests() { - set_script_name("A_004_networking_tests"); + A_004_networking_tests() : TestScript { "A_004_networking_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/testing/test_scripts/A_005_nation_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_005_nation_tests.cpp index 6f91ac2..bfa8a59 100644 --- a/src/openvic-simulation/testing/test_scripts/A_005_nation_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_005_nation_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_005_nation_tests : public TestScript { public: - A_005_nation_tests() { - set_script_name("A_005_nation_tests"); + A_005_nation_tests() : TestScript { "A_005_nation_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/testing/test_scripts/A_006_politics_tests.cpp b/src/openvic-simulation/testing/test_scripts/A_006_politics_tests.cpp index 091075c..f9e93d9 100644 --- a/src/openvic-simulation/testing/test_scripts/A_006_politics_tests.cpp +++ b/src/openvic-simulation/testing/test_scripts/A_006_politics_tests.cpp @@ -5,8 +5,7 @@ namespace OpenVic { class A_006_politics_tests : public TestScript { public: - A_006_politics_tests() { - set_script_name("A_006_politics_tests"); + A_006_politics_tests() : TestScript { "A_006_politics_tests" } { add_requirements(); } diff --git a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp index 6a47194..95d2759 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPoint.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPoint.hpp @@ -6,7 +6,7 @@ #include #include -#include "openvic-simulation/types/fixed_point/FixedPointLUT.hpp" +#include "openvic-simulation/utility/Getters.hpp" #include "openvic-simulation/utility/Logger.hpp" #include "openvic-simulation/utility/NumberUtils.hpp" #include "openvic-simulation/utility/StringUtils.hpp" @@ -18,14 +18,32 @@ namespace OpenVic { static constexpr size_t SIZE = 8; - static constexpr int32_t PRECISION = FPLUT::SIN_LUT_PRECISION; + static constexpr int32_t PRECISION = 16; static constexpr int64_t ONE = 1 << PRECISION; + static constexpr int64_t FRAC_MASK = ONE - 1; + /* Fixed points represent any base 2 number with 48 bits above the point and 16 bits below it. + * - Any number expressible as n / 2^16 where n is an int64_t can be converted to a fixed point exactly. + * - If a number cannot be expressed as an integer divided by 2^16, it will be rounded down to the first + * representable number below it. For example: 0.01 = 655.36 / 2^16 becomes 0.0099945068359375 = 655 / 2^16. + * - While numbers with an integer part greater than 2^32 can be represented, they do not work properly with + * multiplication and division which involve an intermediate value that is 2^16 times larger than the result. + * For numbers with integer part smaller than 2^32 the top 16 bits prevent this intermediate value from + * overflowing. For larger values this will not work and the result will be missing its most significant bits. */ + + private: + int64_t PROPERTY_RW_CUSTOM_NAME(value, get_raw_value, set_raw_value); + + /* Sin lookup table */ + #include "openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp" + + static_assert(SIN_LUT_PRECISION == PRECISION); + + public: constexpr fixed_point_t() : value { 0 } {} constexpr fixed_point_t(int64_t new_value) : value { new_value } {} constexpr fixed_point_t(int32_t new_value) : value { static_cast(new_value) << PRECISION } {} - // Trivial destructor constexpr ~fixed_point_t() = default; static constexpr fixed_point_t max() { @@ -200,6 +218,23 @@ namespace OpenVic { return static_cast(178145LL); } + constexpr fixed_point_t sin() const { + int64_t num = (*this % pi2() * one_div_pi2()).get_raw_value(); + + const bool negative = num < 0; + if (negative) { + num = -num; + } + + const int64_t index = num >> SIN_LUT_SHIFT; + const int64_t a = SIN_LUT[index]; + const int64_t b = SIN_LUT[index + 1]; + + const int64_t fraction = (num - (index << SIN_LUT_SHIFT)) << SIN_LUT_COUNT_LOG2; + const int64_t result = a + (((b - a) * fraction) >> SIN_LUT_PRECISION); + return !negative ? result : -result; + } + constexpr bool is_negative() const { return value < 0; } @@ -216,23 +251,35 @@ namespace OpenVic { // Doesn't account for sign, so -n.abc -> 1 - 0.abc constexpr fixed_point_t get_frac() const { - return value & (ONE - 1); + return value & FRAC_MASK; } constexpr bool is_integer() const { return get_frac() == 0; } - constexpr int64_t to_int64_t() const { - return value >> PRECISION; + constexpr fixed_point_t floor() const { + return value & ~FRAC_MASK; } - constexpr void set_raw_value(int64_t value) { - this->value = value; + constexpr fixed_point_t ceil() const { + return floor() + !is_integer(); } - constexpr int64_t get_raw_value() const { - return value; + /* WARNING: the results of these rounding functions are affected by the accuracy of base 2 fixed point numbers, + * for example 1.0 rounded to a multiple of 0.01 is 0.99945068359375 for down and 1.0094451904296875 for up. */ + constexpr fixed_point_t round_down_to_multiple(fixed_point_t factor) const { + const fixed_point_t remainder = *this % factor; + return *this - remainder - (remainder < 0 ? factor : _0()); + } + + constexpr fixed_point_t round_up_to_multiple(fixed_point_t factor) const { + const fixed_point_t remainder = *this % factor; + return *this - remainder + (remainder > 0 ? factor : _0()); + } + + constexpr int64_t to_int64_t() const { + return value >> PRECISION; } constexpr int32_t to_int32_t() const { @@ -251,13 +298,13 @@ namespace OpenVic { return value / static_cast(ONE); } - constexpr float to_double_rounded() const { + constexpr double to_double_rounded() const { return NumberUtils::round_to_int64((value / static_cast(ONE)) * 100000.0) / 100000.0; } static std::ostream& print(std::ostream& stream, fixed_point_t val, size_t decimal_places = 0) { if (decimal_places > 0) { - fixed_point_t err = fixed_point_t::_0_50(); + fixed_point_t err = _0_50(); for (size_t i = decimal_places; i > 0; --i) { err /= 10; } @@ -612,8 +659,6 @@ namespace OpenVic { } private: - int64_t value; - static constexpr fixed_point_t parse_integer(char const* str, char const* const end, bool* successful) { int64_t parsed_value = StringUtils::string_to_int64(str, end, successful, 10); return parse(parsed_value); diff --git a/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp b/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp deleted file mode 100644 index a5d585f..0000000 --- a/src/openvic-simulation/types/fixed_point/FixedPointLUT.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -namespace OpenVic::FPLUT { - -#include "openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp" - - constexpr int32_t SHIFT = SIN_LUT_PRECISION - SIN_LUT_COUNT_LOG2; - - constexpr int64_t sin(int64_t value) { - int sign = 1; - if (value < 0) { - value = -value; - sign = -1; - } - - int index = value >> SHIFT; - int64_t a = SIN_LUT[index]; - int64_t b = SIN_LUT[index + 1]; - int64_t fraction = (value - (index << SHIFT)) << SIN_LUT_COUNT_LOG2; - int64_t result = a + (((b - a) * fraction) >> SIN_LUT_PRECISION); - return result * sign; - } -} diff --git a/src/openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp b/src/openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp index 0c75efe..2b935a3 100644 --- a/src/openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp +++ b/src/openvic-simulation/types/fixed_point/FixedPointLUT_sin.hpp @@ -1,9 +1,7 @@ -#pragma once - -#include static constexpr int32_t SIN_LUT_PRECISION = 16; static constexpr int32_t SIN_LUT_COUNT_LOG2 = 9; +static constexpr int32_t SIN_LUT_SHIFT = SIN_LUT_PRECISION - SIN_LUT_COUNT_LOG2; static constexpr int64_t SIN_LUT[(1 << SIN_LUT_COUNT_LOG2) + 1] = { 0, 804, 1608, 2412, 3216, 4019, 4821, 5623, 6424, 7224, 8022, 8820, 9616, 10411, 11204, 11996, diff --git a/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp b/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp deleted file mode 100644 index 6cdb926..0000000 --- a/src/openvic-simulation/types/fixed_point/FixedPointMath.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" - -namespace OpenVic::FPMath { - constexpr fixed_point_t sin(fixed_point_t number) { - number %= fixed_point_t::pi2(); - number *= fixed_point_t::one_div_pi2(); - return FPLUT::sin(number.get_raw_value()); - } -} diff --git a/src/openvic-simulation/types/fixed_point/lut_generator/lut_generator.py b/src/openvic-simulation/types/fixed_point/lut_generator/lut_generator.py index 8ae7a32..e20eaa3 100644 --- a/src/openvic-simulation/types/fixed_point/lut_generator/lut_generator.py +++ b/src/openvic-simulation/types/fixed_point/lut_generator/lut_generator.py @@ -20,12 +20,10 @@ def generate_sin_lut(precision : int, count_log2 : int): SinLut.append(SinLut[0]) output = [ - "#pragma once", - "", - "#include ", "", f"static constexpr int32_t SIN_LUT_PRECISION = {precision};", f"static constexpr int32_t SIN_LUT_COUNT_LOG2 = {count_log2};", + "static constexpr int32_t SIN_LUT_SHIFT = SIN_LUT_PRECISION - SIN_LUT_COUNT_LOG2;", "", "static constexpr int64_t SIN_LUT[(1 << SIN_LUT_COUNT_LOG2) + 1] = {" ] diff --git a/src/openvic-simulation/utility/Getters.hpp b/src/openvic-simulation/utility/Getters.hpp index fa76e74..0a6917c 100644 --- a/src/openvic-simulation/utility/Getters.hpp +++ b/src/openvic-simulation/utility/Getters.hpp @@ -121,7 +121,7 @@ ACCESS: #define PROPERTY_RW_FULL(NAME, GETTER_NAME, SETTER_NAME, ACCESS) \ PROPERTY_FULL(NAME, GETTER_NAME, ACCESS) \ public: \ - void SETTER_NAME(decltype(NAME) new_##NAME) { \ + constexpr void SETTER_NAME(decltype(NAME) new_##NAME) { \ NAME = new_##NAME; \ } \ ACCESS: -- cgit v1.2.3-56-ga3b1