La forma más eficiente/elegante de cortar un número?
Dado un real (n), un valor máximo este real puede ser (superior), y un valor mínimo este real puede ser (inferior), ¿cómo podemos recortar más eficientemente n, de modo que permanezca entre inferior y superior?
Por supuesto, el uso de un montón de declaraciones if puede hacer esto, pero eso es aburrido! ¿Qué pasa con soluciones más compactas y elegantes/divertidas?
Mi propio intento rápido (C/C++):
float clip( float n, float lower, float upper )
{
n = ( n > lower ) * n + !( n > lower ) * lower;
return ( n < upper ) * n + !( n < upper ) * upper;
}
Estoy seguro de que hay otras, mejores maneras de hacer esto, es por eso que estoy poniendo esto por ahí..!
12 answers
¿Qué pasa con aburrido, viejo, legible, y más corto todavía:
float clip(float n, float lower, float upper) {
return std::max(lower, std::min(n, upper));
}
?
Esta expresión también podría ser 'genérica' de la siguiente manera:
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 agregó:
Tenga en cuenta que en Windows es posible que tenga que definir NOMINMAX porque definen macros min y max que entran en conflicto
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-01 03:22:00
¿Por qué reescribir algo que ya ha sido escrito para ti?
#include <boost/algorithm/clamp.hpp>
boost::algorithm::clamp(n, lower, upper);
A partir de C++17, esto es ahora parte del STL :
#include <algorithm>
std::clamp(n, lower, upper);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-28 11:01:39
Se espera que C++17 agregue una función clamp. Cortesía de 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 );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-16 20:42:54
Rara vez iría más allá...
return n <= lower ? lower : n >= upper ? upper : n;
Si sabe que puede tenerlos, querrá verificar si NaN / Inf, etc. se conservan....
Digo rara vez y no nunca solo porque a veces menos ramificación puede ser más rápido, pero seguro que desea perfilarlo y demostrar que ayudó y importaba....
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-20 04:48:13
Puede que te guste el operador ternario:
value = value<lower?lower:value;
value = value>upper?upper:value;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-17 06:47:17
Poco elegante, inseguro, costoso pero sin ramificaciones:
n= 0.5 * (n + lower + fabs(n - lower));
n= 0.5 * (n + upper - fabs(upper - n));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-17 09:58:29
La función tangente hiperbólica hace precisamente eso de una manera bastante elegante (se usa mucho para redes neuronales). Véase el código a continuación.
float clip(float x, float min, float max) {
return ((max-min)/2)*((exp(x) - exp(-x))/(exp(x) + exp(-x))) + max - (max-min)/2;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-10 04:59:02
n = n + ((n < lower) * (lower - n)) + ((n > upper) * (upper - n));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 11:36:42
Si el rendimiento realmente le importa, ¿qué pasa con una solución en línea que evita la asignación cuando no se requiere:
#define clip(n, lower, upper) if (n < lower) n= lower; else if (n > upper) n= upper
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-17 09:35:13
El siguiente archivo de cabecera debería funcionar para C y C++. Tenga en cuenta que desactiva min y max si las macros ya están definidas:
#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 */
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-10 19:41:46
Lo mejor es claramente
template <typename t>
t clamp2(t x, t min, t max)
{
if (x < min) x = min;
if (x > max) x = max;
return x;
}
Como se compila a
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
Tiene 0 ramas y debe ser la más rápida de todas las publicadas anteriormente.
También msvc141 con la configuración de versión estándar
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-22 16:08:51
Si desea usar xtensor, soportaría arreglos multidimensionales y la solución sería muy elegante.
#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;
//la Respuesta es { 2, 2, -2, -2 }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 18:43:28