给定一个实数(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;
}
我确信还有其他更好的方法可以做到这一点,这就是我把它放在那里的原因..!
答案 0 :(得分:75)
枯燥,陈旧,可读和最短的东西:
float clip(float n, float lower, float upper) {
return std::max(lower, std::min(n, upper));
}
这个表达式也可以像这样“泛化”:
template <typename T>
T clip(const T& n, const T& lower, const T& upper) {
return std::max(lower, std::min(n, upper));
}
<强>更新强>
Billy ONeal补充道:
请注意,在Windows上,您可能必须定义NOMINMAX,因为它们定义了冲突的最小和最大宏
答案 1 :(得分:35)
为什么要重写一下already been written for you?
#include <boost/algorithm/clamp.hpp>
boost::algorithm::clamp(n, lower, upper);
从C ++ 17开始,现在是part of the STL:
#include <algorithm>
std::clamp(n, lower, upper);
答案 2 :(得分:19)
C ++ 17应该添加clamp函数。由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 );
答案 3 :(得分:15)
我很少超越......
return n <= lower ? lower : n >= upper ? upper : n;
如果你知道你可能有它们,你想检查NaN / Inf等是否被保留....
我很少说,也不仅仅是因为有时候较少的分支可以更快,但你肯定想要描述它并证明它有帮助和重要....
答案 4 :(得分:5)
您可能喜欢三元运算符:
value = value<lower?lower:value;
value = value>upper?upper:value;
答案 5 :(得分:4)
不雅,不安全,昂贵但无分支:
n= 0.5 * (n + lower + fabs(n - lower));
n= 0.5 * (n + upper - fabs(upper - n));
答案 6 :(得分:2)
最好的显然是
template <typename t>
t clamp2(t x, t min, t max)
{
if (x < min) x = min;
if (x > max) x = max;
return x;
}
编译为
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
它有0个分支,应该是上面发布的最快的分支。
还带有标准版本设置的msvc141
答案 7 :(得分:1)
n = n + ((n < lower) * (lower - n)) + ((n > upper) * (upper - n));
答案 8 :(得分:1)
双曲正切函数以非常优雅的方式完成(对神经网络使用很多)。请参阅下面的代码。
.hex-bg {
background-image: url('/images/diamond.png');
background-size: cover;
background-repeat: no-repeat;
background-position:center;
min-height: 30px;
box-sizing:border-box;
padding: 20px;
width:250px;
height:290px;
text-align:center;
color:white;
font-size:14px;
}
.hex-bg img{
max-width:50px;
padding:20px;
}
.text-wrapper{
margin-top:10px;
}
答案 9 :(得分:1)
如果你想使用xtensor,它将支持多维数组,解决方案非常优雅。
#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;
//答案是{2,2,2,-2}
答案 10 :(得分:0)
以下头文件应该适用于C和C ++。请注意,如果宏已经定义,则未定义min和max:
#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 */
答案 11 :(得分:0)
警告任何试图执行此类操作的人,在此情况下,您将锁定输入类型的可能值。
template<typename T>
T clamp(T input)
{
return boost::algorithm::clamp(input,
std::numeric_limits<T>::min(),
std::numeric_limits<T>::max());
}
这对于T
和input
的某些值将失败。例如:
clamp<int16_t>(32768.0);
将返回
-32767
尝试一下,看看。问题在于,在进行比较之前,input
在进入函数时被强制转换为T
。如果您static_cast<int16_t>(+32768)
,您将得到UB。
除了下面的代码“更好”但不完整之外,我没有一个好的解决方案。这适用于较小的整数类型(int16_t
和int32_t
)和单精度float
,但对于int64_t
和double
却有问题。
template<typename T>
T clamp(double input)
{
double intermediate = return boost::algorithm::clamp<double>(input,
std::numeric_limits<T>::min(),
std::numeric_limits<T>::max());
return boost::numeric_cast<T>(intermediate);
}
答案 12 :(得分:-1)
如果性能对您来说真的很重要,那么内联解决方案可以避免在不需要时进行分配:
#define clip(n, lower, upper) if (n < lower) n= lower; else if (n > upper) n= upper