Given a real (n), a maximum value this real can be (upper), and a minimum value this real can be (lower), how can we most efficiently clip n, such that it remains between lo
If performance really matters to you, what about an inline solution that avoids assignment when not required:
#define clip(n, lower, upper) if (n < lower) n= lower; else if (n > upper) n= upper
UPDATE: C++17's <algorithm> header added std::clamp(value, low, high).
In older C++ versions, I'd very rarely go beyond...
return n <= lower ? lower : n >= upper ? upper : n;
...or, if you find it more readable keeping the left-to-right ordering of lower, n and upper...
return n <= lower ? lower : n <= upper ? n : upper;
(using <= lower
is better than < lower
because when n == lower
it avoids having to compare with upper
)
If you know you might have them, you'd want to check if NaN / Inf etc. are preserved....
I say rarely and not never just because sometimes less branching can be faster, but you'd sure want to profile it and prove it helped and mattered....
C++17 is expected to add a clamp function. Courtesy of cppreference.com:
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi );
template<class T, class Compare>
constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp );
What about boring, old, readable, and shortest yet:
float clip(float n, float lower, float upper) {
return std::max(lower, std::min(n, upper));
}
?
This expression could also be 'genericized' like so:
template <typename T>
T clip(const T& n, const T& lower, const T& upper) {
return std::max(lower, std::min(n, upper));
}
Update
Billy ONeal added:
Note that on windows you might have to define NOMINMAX because they define min and max macros which conflict
You might like the ternary operator:
value = value<lower?lower:value;
value = value>upper?upper:value;