Je voudrais fixer une valeur x
à une plage [a, b]
:
x = (x < a) ? a : ((x > b) ? b : x);
C'est assez basique. Mais je ne vois pas de fonction "clamp" dans la bibliothèque de classes - du moins pas dans System.Math
.
(Pour ceux qui ne savent pas "bloquer" une valeur, il faut s'assurer qu'elle se situe entre des valeurs maximales et minimales. Si elle est supérieure à la valeur max, elle est remplacée par la valeur max, etc.)
Réponses:
Vous pouvez écrire une méthode d'extension:
Les méthodes d'extension vont dans des classes statiques - puisqu'il s'agit d'une fonction de bas niveau, elle devrait probablement aller dans un espace de noms de base de votre projet. Vous pouvez ensuite utiliser la méthode dans n'importe quel fichier de code contenant une directive using pour l'espace de noms, par exemple
.NET Core 2.0
À partir de .NET Core 2.0,
System.Math
uneClamp
méthode peut être utilisée à la place:la source
IComparable
est qu'aucune boxe ne se produit. Cela devrait fonctionner très vite. N'oubliez pas qu'avecdouble
etfloat
, laCompareTo
méthode correspond à un ordre total oùNaN
est inférieur à toutes les autres valeurs, y comprisNegativeInfinity
. Ce n'est donc pas équivalent à l'<
opérateur. Si vous avez utilisé<
avec un type à virgule flottante, vous devrez également réfléchir à la façon de traiterNaN
. Cela n'est pas pertinent pour les autres types numériques.NaN
dans les deux cas. La version avec<
et>
produiraitNaN
et utiliseraitNaN
pourmin
oumax
ferait effectivement une pince unilatérale. AvecCompareTo
ça reviendrait toujoursNaN
simax
c'estNaN
.Utilisez simplement
Math.Min
etMath.Max
:la source
int a0 = x > a ? x : a; return a0 < b ? a0 : b
que (bien que donne des résultats corrects) n'est pas exactement idéal.Math.Min(Math.Max(x, min), max)
entraîne une comparaison de plus que nécessaire si x <min.Essayer:
la source
Il n'y en a pas, mais ce n'est pas trop difficile d'en faire un. J'en ai trouvé un ici: pince
C'est:
Et il peut être utilisé comme:
la source
Clamp(T value, T min, T max)
Il n'y en a pas dans l'
System.Math
espace de noms .Il existe une
MathHelper
classe où elle est disponible pour le studio de jeu XNA si c'est ce que vous faites:la source
Je partage simplement la solution de Lee avec les problèmes et préoccupations des commentaires traités, dans la mesure du possible:
Différences:
ed
) pour (plus loin) indiquer que la valeur n'est pas bloquée sur place, et qu'à la place, une nouvelle valeur est renvoyée (voir le commentaire de @ JimBalter ).null check
sur toutes les entrées (voir @ commentaire de JeppeStigNielsen ).min
etmax
ifmin > max
(Voir le commentaire de @ JeppeStigNielsen ).Limitations: pas de pinces unilatérales. Si
max
estNaN
, renvoie toujoursNaN
(voir le commentaire d'Herman ).la source
nameof
ne fonctionne pas pour C # 5 ou inférieur.En utilisant les réponses précédentes, je l'ai condensé au code ci-dessous pour mes besoins. Cela vous permettra également de fixer un nombre uniquement par son min ou son max.
la source
return value.ClampedMinimum(min).ClampedMaximum(max);
?Le code ci-dessous prend en charge la spécification de limites dans n'importe quel ordre (c'est
bound1 <= bound2
-à- dire oubound2 <= bound1
). J'ai trouvé cela utile pour les valeurs de serrage calculées à partir d'équations linéaires (y=mx+b
) où la pente de la ligne peut être croissante ou décroissante.Je sais: le code se compose de cinq opérateurs d'expression conditionnelle super-laids . Le fait est que cela fonctionne et les tests ci-dessous le prouvent. N'hésitez pas à ajouter des parenthèses strictement inutiles si vous le souhaitez.
Vous pouvez facilement créer d'autres surcharges pour d'autres types numériques et copier / coller les tests.
Attention: comparer des nombres à virgule flottante n'est pas simple. Ce code n'implémente pas les
double
comparaisons de manière robuste. Utilisez une bibliothèque de comparaison à virgule flottante pour remplacer les utilisations des opérateurs de comparaison.Tests xUnit / FluentAssertions:
la source
Si je veux valider la plage d'un argument dans [min, max], j'utilise la classe pratique suivante:
La classe fonctionne pour tous les objets qui le sont
IComparable
. Je crée une instance avec une certaine plage:Je valide soit un argument
ou fixez l'argument à la plage:
la source