diff --git a/include/utils/math.h b/include/utils/math.h index bb911f67b7..f1ad772c72 100644 --- a/include/utils/math.h +++ b/include/utils/math.h @@ -13,37 +13,97 @@ namespace cura { +/** + * @brief Returns the square of a value. + * + * @tparam T A multipliable type (arithmetic types such as int, float, double, etc.) + * @param a The value to be squared. + * @return T The square of the input value. + */ template [[nodiscard]] T square(const T& a) { return a * a; } -[[nodiscard]] inline int64_t round_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer +/** + * @brief Returns the quotient of the division of two signed integers, rounded to the nearest integer. + * + * @param dividend The numerator. + * @param divisor The denominator (must not be zero). + * @return int64_t The result of the division rounded to the nearest integer. + * @throws std::invalid_argument If the divisor is zero. + */ +[[nodiscard]] inline int64_t round_divide_signed(const int64_t dividend, const int64_t divisor) { - if ((dividend < 0) ^ (divisor < 0)) // Either the numerator or the denominator is negative, so the result must be negative. + if ((dividend < 0) ^ (divisor < 0)) { - return (dividend - divisor / 2) / divisor; // Flip the .5 offset to do proper rounding in the negatives too. + return (dividend - divisor / 2) / divisor; } return (dividend + divisor / 2) / divisor; } -[[nodiscard]] inline uint64_t ceil_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded up towards positive infinity. +/** + * @brief Returns the quotient of the division of two signed integers, rounded up towards positive infinity. + * + * @param dividend The numerator. + * @param divisor The denominator (must not be zero). + * @return int64_t The result of the division rounded up. + * @throws std::invalid_argument If the divisor is zero. + */ +[[nodiscard]] inline int64_t ceil_divide_signed(const int64_t dividend, const int64_t divisor) { - return static_cast((dividend / divisor) + (dividend * divisor > 0 ? 1 : 0)); + int64_t quotient = dividend / divisor; + int64_t remainder = dividend % divisor; + + // Round up if there's a remainder and the signs of dividend and divisor are the same + if (remainder != 0 && ((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0))) + { + quotient += 1; + } + + return quotient; } -[[nodiscard]] inline uint64_t floor_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded down towards negative infinity. +/** + * @brief Returns the quotient of the division of two signed integers, rounded down towards negative infinity. + * + * @param dividend The numerator. + * @param divisor The denominator (must not be zero). + * @return int64_t The result of the division rounded down. + * @throws std::invalid_argument If the divisor is zero. + */ +[[nodiscard]] inline int64_t floor_divide_signed(const int64_t dividend, const int64_t divisor) { - return static_cast((dividend / divisor) + (dividend * divisor > 0 ? 0 : -1)); + const int64_t quotient = dividend / divisor; + const int64_t remainder = dividend % divisor; + if (remainder != 0 && ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0))) + { + return quotient - 1; + } + return quotient; } -[[nodiscard]] inline uint64_t round_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer +/** + * @brief Returns the quotient of the division of two unsigned integers, rounded to the nearest integer. + * + * @param dividend The numerator. + * @param divisor The denominator (must not be zero). + * @return uint64_t The result of the division rounded to the nearest integer. + */ +[[nodiscard]] inline uint64_t round_divide(const uint64_t dividend, const uint64_t divisor) { return (dividend + divisor / 2) / divisor; } -[[nodiscard]] inline uint64_t round_up_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer +/** + * @brief Returns the quotient of the division of two unsigned integers, rounded up towards positive infinity. + * + * @param dividend The numerator. + * @param divisor The denominator (must not be zero). + * @return uint64_t The result of the division rounded up. + */ +[[nodiscard]] inline uint64_t round_up_divide(const uint64_t dividend, const uint64_t divisor) { return (dividend + divisor - 1) / divisor; } diff --git a/tests/utils/MathTest.cpp b/tests/utils/MathTest.cpp new file mode 100644 index 0000000000..71c5e8c8f9 --- /dev/null +++ b/tests/utils/MathTest.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "utils/math.h" + +#include + +#include + +namespace cura +{ +// NOLINTBEGIN(*-magic-numbers) + +// Test cases for the square function +TEST(MathTest, TestSquare) +{ + EXPECT_EQ(square(2), 4) << "Square of 2 should be 4."; + EXPECT_EQ(square(-3), 9) << "Square of -3 should be 9."; + EXPECT_EQ(square(0), 0) << "Square of 0 should be 0."; + EXPECT_EQ(square(1.5), 2.25) << "Square of 1.5 should be 2.25."; +} + +// Test cases for the round_divide_signed function +TEST(MathTest, TestRoundDivideSigned) +{ + EXPECT_EQ(round_divide_signed(10, 3), 3) << "10 / 3 rounded should be 3."; + EXPECT_EQ(round_divide_signed(10, -3), -3) << "10 / -3 rounded should be -3."; + EXPECT_EQ(round_divide_signed(-10, 3), -3) << "-10 / 3 rounded should be -3."; + EXPECT_EQ(round_divide_signed(-10, -3), 3) << "-10 / -3 rounded should be 3."; +} + +// Test cases for the ceil_divide_signed function +TEST(MathTest, TestCeilDivideSigned) +{ + EXPECT_EQ(ceil_divide_signed(10, 3), 4) << "10 / 3 rounded up should be 4."; + EXPECT_EQ(ceil_divide_signed(10, -3), -3) << "10 / -3 rounded up should be -3."; + EXPECT_EQ(ceil_divide_signed(-10, 3), -3) << "-10 / 3 rounded up should be -3."; + EXPECT_EQ(ceil_divide_signed(-10, -3), 4) << "-10 / -3 rounded up should be 4."; +} + +// Test cases for the floor_divide_signed function +TEST(MathTest, TestFloorDivideSigned) +{ + EXPECT_EQ(floor_divide_signed(10, 3), 3) << "10 / 3 rounded down should be 3."; + EXPECT_EQ(floor_divide_signed(10, -3), -4) << "10 / -3 rounded down should be -4."; + EXPECT_EQ(floor_divide_signed(-10, 3), -4) << "-10 / 3 rounded down should be -4."; + EXPECT_EQ(floor_divide_signed(-10, -3), 3) << "-10 / -3 rounded down should be 3."; +} + +// Test cases for the round_divide function +TEST(MathTest, TestRoundDivide) +{ + EXPECT_EQ(round_divide(10, 3), 3) << "10 / 3 rounded should be 3."; + EXPECT_EQ(round_divide(11, 3), 4) << "11 / 3 rounded should be 4."; + EXPECT_EQ(round_divide(9, 3), 3) << "9 / 3 rounded should be 3."; + +} + +// Test cases for the round_up_divide function +TEST(MathTest, TestRoundUpDivide) +{ + EXPECT_EQ(round_up_divide(10, 3), 4) << "10 / 3 rounded up should be 4."; + EXPECT_EQ(round_up_divide(9, 3), 3) << "9 / 3 rounded up should be 3."; + EXPECT_EQ(round_up_divide(1, 1), 1) << "1 / 1 rounded up should be 1."; +} + +// NOLINTEND(*-magic-numbers) + +} // namespace cura