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
The following header file should work for C and C++. Note that it undefines min and max if the macros are already defined:
#pragma once
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#ifdef __cplusplus
#include <algorithm>
template <typename T>
T clip(T in, T low, T high)
{
return std::min(std::max(in, low), high);
}
#else /* !__cplusplus */
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) < (b)) ? (b) : (a))
#define clip(a, b, c) min(max((a), (b)), (c))
#endif /* __cplusplus */
Inelegant, unsafe, costly but branchless:
n= 0.5 * (n + lower + fabs(n - lower));
n= 0.5 * (n + upper - fabs(upper - n));
the best is clearly
template <typename t>
t clamp2(t x, t min, t max)
{
if (x < min) x = min;
if (x > max) x = max;
return x;
}
as it compiles to
movss xmm0, cs:__real@c2c80000
maxss xmm0, [rsp+38h+var_18]
movss xmm1, cs:__real@42c80000
minss xmm1, xmm0
movss [rsp+38h+var_18], xmm1
it has 0 branches and should be the fastest of all posted above.
also msvc141 with the standard release settings
Why rewrite something that's already been written for you?
#include <boost/algorithm/clamp.hpp>
boost::algorithm::clamp(n, lower, upper);
As of C++17, this is now part of the STL:
#include <algorithm>
std::clamp(n, lower, upper);
n = n + ((n < lower) * (lower - n)) + ((n > upper) * (upper - n));
If you wish to use xtensor, it would support multi-dimensional arrays and the solution would be very elegant.
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xview.hpp"
#include "xtensor/xrandom.hpp"
xt::xarray<float> ar({2.1, 2.9, -2.1, -2.9});
std::cout<<xt::cast<int>(xt::trunc(ar))<<std::endl;
//Answer is { 2, 2, -2, -2 }