BLI: support mod_periodic on integer types
See #125876 for more details. Pull Request: https://projects.blender.org/blender/blender/pulls/125876
This commit is contained in:
committed by
Jacques Lucke
parent
b0a9e45cb5
commit
dceccfda5a
@@ -103,19 +103,19 @@ template<typename T> inline T round(const T &a)
|
||||
|
||||
/**
|
||||
* Repeats the saw-tooth pattern even on negative numbers.
|
||||
* ex: `mod_periodic(-3, 4) = 1`, `mod(-3, 4)= -3`
|
||||
* ex: `mod_periodic(-3, 4) = 1`, `mod(-3, 4)= -3`. This will cause undefined behavior for negative
|
||||
* b.
|
||||
*/
|
||||
template<typename T> inline T mod_periodic(const T &a, const T &b)
|
||||
{
|
||||
BLI_assert(b > 0);
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
BLI_assert(std::numeric_limits<T>::max() - math::abs(a) >= b);
|
||||
return ((a % b) + b) % b;
|
||||
}
|
||||
|
||||
return a - (b * math::floor(a / b));
|
||||
}
|
||||
template<> inline int64_t mod_periodic(const int64_t &a, const int64_t &b)
|
||||
{
|
||||
int64_t c = (a >= 0) ? a : (-1 - a);
|
||||
int64_t tmp = c - (b * (c / b));
|
||||
/* Negative integers have different rounding that do not match floor(). */
|
||||
return (a >= 0) ? tmp : (b - 1 - tmp);
|
||||
}
|
||||
|
||||
template<typename T> inline T ceil(const T &a)
|
||||
{
|
||||
|
||||
@@ -211,4 +211,40 @@ TEST(math_base, FlooredFMod)
|
||||
EXPECT_FLOAT_EQ(floored_fmod(12345.0f, 12345.0f), 0.0f);
|
||||
}
|
||||
|
||||
TEST(math_base, ModPeriodic)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(3.27f, 1.57f), 0.12999988f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(327.f, 47.f), 45.f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(-0.1f, 1.0f), 0.9f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(-0.9f, 1.0f), 0.1f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(-100.1f, 1.0f), 0.90000153f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(-0.1f, 12345.0f), 12344.9f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(12345.1f, 12345.0f), 0.099609375f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(12344.999f, 12345.0f), 12344.999f);
|
||||
EXPECT_FLOAT_EQ(math::mod_periodic(12345.0f, 12345.0f), 0.0f);
|
||||
|
||||
EXPECT_EQ(math::mod_periodic(1, 10), 1);
|
||||
EXPECT_EQ(math::mod_periodic(11, 10), 1);
|
||||
EXPECT_EQ(math::mod_periodic(-1, 10), 9);
|
||||
EXPECT_EQ(math::mod_periodic(-11, 10), 9);
|
||||
EXPECT_EQ(math::mod_periodic(1, 1), 0);
|
||||
EXPECT_EQ(math::mod_periodic(0, 99999), 0);
|
||||
EXPECT_EQ(math::mod_periodic(99999, 99999), 0);
|
||||
|
||||
EXPECT_EQ(
|
||||
math::mod_periodic(std::numeric_limits<int>::max() / 2, std::numeric_limits<int>::max() / 2),
|
||||
0);
|
||||
EXPECT_EQ(
|
||||
math::mod_periodic(std::numeric_limits<int>::min() / 2, std::numeric_limits<int>::max() / 2),
|
||||
std::numeric_limits<int>::max() / 2 - 1);
|
||||
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(1, 10), 1);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(11, 10), 1);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(-1, 10), 9);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(-11, 10), 9);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(1, 1), 0);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(0, 99999), 0);
|
||||
EXPECT_EQ(math::mod_periodic<int64_t>(99999, 99999), 0);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
||||
Reference in New Issue
Block a user