C++ 剪辑数字的最有效/优雅的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9323903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Most efficient/elegant way to clip a number?
提问by Alex Z
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 lower and upper?
给定一个实数 (n),这个实数可以是的最大值(上),以及这个实数可以是的最小值(下),我们如何最有效地裁剪 n,使其保持在下限和上限之间?
Of course, using a bunch of if statements can do this, but that's boring! What about more compact and elegant/fun solutions?
当然,使用一堆 if 语句可以做到这一点,但这很无聊!更紧凑和优雅/有趣的解决方案怎么样?
My own quick attempt (C/C++):
我自己的快速尝试(C/C++):
float clip( float n, float lower, float upper )
{
n = ( n > lower ) * n + !( n > lower ) * lower;
return ( n < upper ) * n + !( n < upper ) * upper;
}
I'm sure there are other, better ways to do this, that's why I'm putting this out there..!
我敢肯定还有其他更好的方法可以做到这一点,这就是我将它放在那里的原因..!
回答by justin
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
请注意,在 Windows 上,您可能必须定义 NOMINMAX,因为它们定义了冲突的最小和最大宏
回答by Riot
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:
从 C++17 开始,这现在是 STL 的一部分:
#include <algorithm>
std::clamp(n, lower, upper);
回答by Josh Kelley
C++17 is expected to add a clampfunction. Courtesy of cppreference.com:
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 );
回答by Tony Delroy
UPDATE: C++17's <algorithm>
header added std::clamp(value, low, high)
.
更新:<algorithm>
添加了C++17 的头文件std::clamp(value, low, high)
。
In older C++ versions, I'd very rarely go beyond...
在旧的 C++ 版本中,我很少超越......
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...
...或者,如果您发现保持下、n 和上的从左到右的顺序更具可读性...
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
)
(使用<= lower
比< lower
因为n == lower
避免与 进行比较时更好upper
)
If you know you might have them, you'd want to check if NaN / Inf etc. are preserved....
如果你知道你可能有它们,你会想检查是否保留了 NaN / Inf 等......
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....
我说很少而不是从不只是因为有时更少的分支可以更快,但是您肯定想对其进行概要分析并证明它有帮助和重要....
回答by Yves Daoust
Inelegant, unsafe, costly but branchless:
不优雅、不安全、昂贵但没有分支:
n= 0.5 * (n + lower + fabs(n - lower));
n= 0.5 * (n + upper - fabs(upper - n));
回答by Rich
You might like the ternary operator:
您可能喜欢三元运算符:
value = value<lower?lower:value;
value = value>upper?upper:value;
回答by nsn
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.
它有 0 个分支,应该是上面发布的所有分支中最快的。
also msvc141 with the standard release settings
还有 msvc141 与标准发布设置
回答by Achyut Sarma
If you wish to use xtensor, it would support multi-dimensional arrays and the solution would be very elegant.
如果您希望使用 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;
//Answer is { 2, 2, -2, -2 }
//答案是{ 2, 2, -2, -2 }
回答by user997112
n = n + ((n < lower) * (lower - n)) + ((n > upper) * (upper - n));
回答by Woody
The following header file should work for C and C++. Note that it undefines min and max if the macros are already defined:
以下头文件应该适用于 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 */