Me gustaría fijar un valor x
a un rango [a, b]
:
x = (x < a) ? a : ((x > b) ? b : x);
Esto es bastante básico. Pero no veo una función "clamp" en la biblioteca de clases, al menos no en System.Math
.
(Para los que no lo saben, "sujetar" un valor es asegurarse de que se encuentra entre algunos valores máximos y mínimos. Si es mayor que el valor máximo, entonces se reemplaza por el máximo, etc.)
Respuestas:
Podrías escribir un método de extensión:
Los métodos de extensión van en clases estáticas; dado que esta es una función de nivel bastante bajo, probablemente debería ir en algún espacio de nombres central en su proyecto. Luego puede usar el método en cualquier archivo de código que contenga una directiva using para el espacio de nombres, por ejemplo
.NET Core 2.0
Comenzando con .NET Core 2.0
System.Math
ahora tiene unClamp
método que se puede usar en su lugar:fuente
IComparable
es que no se produce boxeo. Esto debería funcionar muy rápido. Recuerde que condouble
yfloat
, elCompareTo
método corresponde a un orden total dondeNaN
es menor que todos los demás valores, incluidosNegativeInfinity
. Entonces no es equivalente al<
operador. Si lo usó<
con un tipo de punto flotante, también tendría que considerar cómo tratarNaN
. Esto no es relevante para otros tipos numéricos.NaN
en cualquier caso. La versión con<
y>
haría de salidaNaN
y el usoNaN
demin
omax
va en detrimento de una pinza de un solo lado. ConCompareTo
ella siempre volveríaNaN
simax
esNaN
.Solo usa
Math.Min
yMath.Max
:fuente
int a0 = x > a ? x : a; return a0 < b ? a0 : b
que (aunque da resultados correctos) no es exactamente lo ideal.Math.Min(Math.Max(x, min), max)
resulta en una comparación más de la necesaria si x <min.Tratar:
fuente
No hay uno, pero no es demasiado difícil hacer uno. Encontré uno aquí: abrazadera
Es:
Y se puede usar como:
fuente
Clamp(T value, T min, T max)
No hay uno en el
System.Math
espacio de nombres .Hay una
MathHelper
clase en la que está disponible para el estudio de juegos XNA si eso es lo que estás haciendo:fuente
Simplemente compartiendo la solución de Lee con los problemas e inquietudes de los comentarios abordados, cuando sea posible:
Diferencias:
ed
) para (más) indicar que el valor no se fija en el lugar y que, en cambio, se devuelve un nuevo valor (ver el comentario de @ JimBalter ).null check
en todas las entradas (ver el comentario de @ JeppeStigNielsen ).min
ymax
ifmin > max
(ver el comentario de @ JeppeStigNielsen ).Limitaciones: No se permiten abrazaderas unilaterales. Si
max
esNaN
, siempre regresaNaN
(Ver comentario de Herman ).fuente
nameof
que no funciona para C # 5 o inferior.Usando las respuestas anteriores, lo condensé en el siguiente código para mis necesidades. Esto también le permitirá fijar un número solo por su mínimo o máximo.
fuente
return value.ClampedMinimum(min).ClampedMaximum(max);
?El siguiente código admite la especificación de límites en cualquier orden (es decir
bound1 <= bound2
, obound2 <= bound1
). Encontré esto útil para fijar valores calculados a partir de ecuaciones lineales (y=mx+b
) donde la pendiente de la línea puede aumentar o disminuir.Lo sé: el código consta de cinco operadores de expresión condicional súper feos . La cosa es que funciona , y las pruebas a continuación lo demuestran. No dude en agregar paréntesis estrictamente innecesarios si así lo desea.
Puede crear fácilmente otras sobrecargas para otros tipos numéricos y básicamente copiar / pegar las pruebas.
Advertencia: comparar números de punto flotante no es sencillo. Este código no implementa
double
comparaciones de manera sólida. Utilice una biblioteca de comparación de punto flotante para reemplazar los usos de los operadores de comparación.Pruebas de xUnit / FluentAssertions:
fuente
Si quiero validar el rango de un argumento en [min, max], uso la siguiente clase útil:
La clase funciona para todos los objetos que son
IComparable
. Creo una instancia con un cierto rango:Yo valido un argumento
o sujete el argumento al rango:
fuente