Skip to content
This repository has been archived by the owner on Nov 17, 2021. It is now read-only.

Make wrap() work with integer types #145

Merged
merged 4 commits into from
Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions matrix/helper_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,64 @@ bool isEqualF(const Type x, const Type y, const Type eps = 1e-4f)
|| (isinf(x) && isinf(y) && isnan(x - y));
}

namespace detail
{

template<typename Floating>
Floating wrap_floating(Floating x, Floating low, Floating high) {
// already in range
if (low <= x && x < high) {
return x;
}

const auto range = high - low;
const auto inv_range = Floating(1) / range; // should evaluate at compile time, multiplies below at runtime
const auto num_wraps = floor((x - low) * inv_range);
return x - range * num_wraps;
}

} // namespace detail

/**
* Wrap value to stay in range [low, high)
* Wrap single precision floating point value to stay in range [low, high)
*
* @param x input possibly outside of the range
* @param low lower limit of the allowed range
* @param high upper limit of the allowed range
* @return wrapped value inside the range
*/
template<typename Type>
Type wrap(Type x, Type low, Type high) {
// already in range
if (low <= x && x < high) {
return x;
}
float wrap(float x, float low, float high) {
return matrix::detail::wrap_floating(x, low, high);
}

const Type range = high - low;
const Type inv_range = Type(1) / range; // should evaluate at compile time, multiplies below at runtime
const Type num_wraps = floor((x - low) * inv_range);
return x - range * num_wraps;
/**
* Wrap double precision floating point value to stay in range [low, high)
*
* @param x input possibly outside of the range
* @param low lower limit of the allowed range
* @param high upper limit of the allowed range
* @return wrapped value inside the range
*/
double wrap(double x, double low, double high) {
return matrix::detail::wrap_floating(x, low, high);
}

/**
* Wrap integer value to stay in range [low, high)
*
* @param x input possibly outside of the range
* @param low lower limit of the allowed range
* @param high upper limit of the allowed range
* @return wrapped value inside the range
*/
template<typename Integer>
Integer wrap(Integer x, Integer low, Integer high) {
const auto range = high - low;

if (x < low)
x += range * ((low - x) / range + 1);

return low + (x - low) % range;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions test/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ int main()
TEST(fabs(wrap(360. - FLT_EPSILON, 0., 360.) - (360. - FLT_EPSILON)) < FLT_EPSILON);
TEST(fabs(wrap(360. + FLT_EPSILON, 0., 360.) - FLT_EPSILON) < FLT_EPSILON);

// integer wraps
TEST(wrap(-10, 0, 10) == 0);
TEST(wrap(-4, 0, 10) == 6);
TEST(wrap(0, 0, 10) == 0)
TEST(wrap(4, 0, 10) == 4);
TEST(wrap(10, 0, 10) == 0);

// wrap pi
TEST(fabs(wrap_pi(0.)) < FLT_EPSILON);
TEST(fabs(wrap_pi(4.) - (4. - M_TWOPI)) < FLT_EPSILON);
Expand Down