diff --git a/include/utils/math.hpp b/include/utils/math.hpp index bf0f679d..f0ac43b7 100644 --- a/include/utils/math.hpp +++ b/include/utils/math.hpp @@ -10,10 +10,10 @@ namespace math_util { /** * Limit value T by min and max bounds */ - template - T cap(T value, T min_value, T max_value) { - value = std::min(value, max_value); - value = std::max(value, min_value); + template + ValueType cap(ValueType value, ValueType min_value, ValueType max_value) { + value = std::min(value, max_value); + value = std::max(value, min_value); return value; } @@ -21,10 +21,25 @@ namespace math_util { * Calculate the percentage for a value * within given range */ - template - int percentage(T value, T min_value, T max_value) { - T percentage = ((value - min_value) / (max_value - min_value)) * 100.0f + 0.5f; - return cap(std::ceil(percentage), 0, 100); + template + ReturnType percentage(ValueType value, ValueType min_value, ValueType max_value) { + auto upper = (max_value - min_value); + auto lower = static_cast(value - min_value); + ValueType percentage = (lower / upper) * 100.0f; + if (std::is_integral()) + percentage += 0.5f; + return cap(percentage, 0.0f, 100.0f); + } + + /** + * Get value for percentage of `max_value` + */ + template + ReturnType percentage_to_value(ValueType percentage, ValueType max_value) { + if (std::is_integral()) + return cap(percentage * max_value / 100.0f + 0.5f, 0, max_value); + else + return cap(percentage * max_value / 100.0f, 0.0f, max_value); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 73bfd197..898311db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,6 +12,7 @@ function(unit_test file) add_test(unit_test.${testname} unit_test.${testname}) endfunction() +unit_test("utils/math") unit_test("utils/memory") unit_test("utils/string") unit_test("components/command_line") diff --git a/tests/unit_tests/utils/math.cpp b/tests/unit_tests/utils/math.cpp new file mode 100644 index 00000000..fe30ffe8 --- /dev/null +++ b/tests/unit_tests/utils/math.cpp @@ -0,0 +1,44 @@ +#include "utils/math.hpp" + +int main() { + using namespace lemonbuddy; + + "cap"_test = [] { + expect(math_util::cap(8, 0, 10) == 8); + expect(math_util::cap(-8, 0, 10) == 0); + expect(math_util::cap(15, 0, 10) == 10); + expect(math_util::cap(20.5f, 0.0f, 30.0f) == 20.5f); + expect(math_util::cap(1.0f, 0.0f, 2.0f) == 1.0f); + expect(math_util::cap(-2.0f, -5.0f, 5.0f) == -2.0f); + expect(math_util::cap(1.0f, 0.0f, 0.0f) == 0); + }; + + "percentage"_test = [] { + expect(math_util::percentage(5.5f, 0.0f, 10.0f) == 55.0f); + expect(math_util::percentage(5.55f, 0.0f, 10.0f) == 56); + expect(math_util::percentage(5.25f, 0.0f, 12.0f) == 43.75f); + expect(math_util::percentage(5, 0, 12) == 41); + expect(math_util::percentage(20.5f, 0.0f, 100.0f) == 20.5f); + expect(math_util::percentage(4.5f, 1.0f, 6.0f) == 70.0f); + expect(math_util::percentage(20.5f, 0.0f, 100.0f) == 21); + expect(math_util::percentage(4, 2, 6) == 50); + expect(math_util::percentage(0, -10, 10) == 50); + expect(math_util::percentage(-10, -10, 10) == 0); + expect(math_util::percentage(10, -10, 10) == 100); + expect(math_util::percentage(10, 0, 100) == 10); + }; + + "percentage_to_value"_test = [] { + expect(math_util::percentage_to_value(50, 5) == 3); + expect(math_util::percentage_to_value(50, 5) == 2.5f); + expect(math_util::percentage_to_value(0, 5) == 0); + expect(math_util::percentage_to_value(10, 5) == 1); + expect(math_util::percentage_to_value(20, 5) == 1); + expect(math_util::percentage_to_value(30, 5) == 2); + expect(math_util::percentage_to_value(40, 5) == 2); + expect(math_util::percentage_to_value(50, 5) == 3); + expect(math_util::percentage_to_value(100, 5) == 5); + expect(math_util::percentage_to_value(200, 5) == 5); + expect(math_util::percentage_to_value(-30, 5) == 0); + }; +}