剪辑数字最有效/优雅的方式?

Ale*_*x Z 47 c++ algorithm math logic

给定一个实数(n),这个实数可以是(上)的最大值,这个实数可以是(更低)的最小值,我们怎样才能最有效地剪切n,使它保持在低位和高位之间?

当然,使用一堆if语句可以做到这一点,但那很无聊!更紧凑,优雅/有趣的解决方案呢?

我自己的快速尝试(C/C++):

float clip( float n, float lower, float upper )
{
    n = ( n > lower ) * n + !( n > lower ) * lower;
    return ( n < upper ) * n + !( n < upper ) * upper;
}
Run Code Online (Sandbox Code Playgroud)

我确信还有其他更好的方法可以做到这一点,这就是为什么我把它放在那里......!

jus*_*tin 79

无聊,旧,可读和最短的东西:

float clip(float n, float lower, float upper) {
  return std::max(lower, std::min(n, upper));
}
Run Code Online (Sandbox Code Playgroud)

这个表达式也可以像这样"泛化":

template <typename T>
T clip(const T& n, const T& lower, const T& upper) {
  return std::max(lower, std::min(n, upper));
}
Run Code Online (Sandbox Code Playgroud)

更新

Billy ONeal补充道:

请注意,在Windows上,您可能必须定义NOMINMAX,因为它们定义了冲突的最小和最大宏

  • 这属于标准.C++ 1z,有人吗? (4认同)
  • 不乏味,有趣!:P (2认同)
  • +1 - 足够好,我删除了我的答案.请注意,在Windows上,您可能必须定义`NOMINMAX`,因为它们定义冲突的最小和最大宏:( (2认同)

Rio*_*iot 41

为什么重写已经为你写的东西

#include <boost/algorithm/clamp.hpp>
boost::algorithm::clamp(n, lower, upper);
Run Code Online (Sandbox Code Playgroud)

从C++ 17开始,这现在是STL的一部分:

#include <algorithm>
std::clamp(n, lower, upper);
Run Code Online (Sandbox Code Playgroud)

  • 标准答案:因为不是每个人都愿意/允许/身体能够吸引Boost.但是,建议将此实现迁移到stdlib,但不知道当前状态. (21认同)
  • 看起来它在C++ 17中是标准的:http://en.cppreference.com/w/cpp/algorithm/clamp (11认同)
  • @TrevorBoydSmith我没有任何反对Boost的东西,而且你不需要你为这个做出相当人为的传福音.也就是说,在评估人们不仅仅做你想做的事情和使用Boost的通常原因时我似乎并没有错,而且令人惊讶的是,并不是因为他们只是想通过"避免"来惹恼你使用良好的同行评审便携式代码".我也不明白为什么你编辑这个现有的答案是完全不同的时候(A)你可以发布你自己的,但也(B)其他人已经有,但没关系. (5认同)

Jos*_*ley 20

C++ 17有望增加钳位功能.由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 );
Run Code Online (Sandbox Code Playgroud)


Ton*_*roy 16

我很少超越......

return n <= lower ? lower : n >= upper ? upper : n;
Run Code Online (Sandbox Code Playgroud)

如果你知道你可能有它们,你想检查NaN/Inf等是否被保留....

我很少说,也绝不仅仅因为有时较少的分支可以更快,但你肯定想要描述它并证明它有帮助和重要....


小智 6

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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

it has 0 branches and should be the fastest of all posted above.

also msvc141 with the standard release settings


Ric*_*ich 5

您可能喜欢三元运算符:

value = value<lower?lower:value;
value = value>upper?upper:value;
Run Code Online (Sandbox Code Playgroud)


Yve*_*ust 5

优雅,不安全,昂贵但无分支机构:

n= 0.5 * (n + lower + fabs(n - lower));
n= 0.5 * (n + upper - fabs(upper - n));
Run Code Online (Sandbox Code Playgroud)

  • 假设“ x &lt;0”的评估实际上是无分支的。从浮点表示中提取符号位(msb),清楚地记录不可移植性,该怎么办?:-) (4认同)
  • 这是我最喜欢的,因为它过于呆板。但fabs()可能包含分支,具体取决于您的库。要成为* REALLY *无分支的,您可以将`fabs(x)`替换为`(x *(1 +(x &lt;0)* -2)` (3认同)