Skip to content

Commit

Permalink
refactor-improve-math-functions (#2135)
Browse files Browse the repository at this point in the history
  • Loading branch information
HellAholic authored Sep 5, 2024
2 parents 8868c17 + 953714c commit 5c8de19
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 9 deletions.
78 changes: 69 additions & 9 deletions include/utils/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<utils::multipliable T>
[[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<uint64_t>((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<uint64_t>((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;
}
Expand Down
69 changes: 69 additions & 0 deletions tests/utils/MathTest.cpp
Original file line number Diff line number Diff line change
@@ -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 <stdexcept>

#include <gtest/gtest.h>

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

0 comments on commit 5c8de19

Please sign in to comment.