質問
値を固定したいのですが x
範囲へ [a, b]
:
x = (x < a) ? a : ((x > b) ? b : x);
これは非常に基本的です。しかし、クラスライブラリに「クランプ」という関数が表示されません - 少なくともではありません System.Math
.
(気づいていないことは、値を「クランプ」することです。最大値と最小値の間にあることを確認することです。最大値よりも大きい場合は、最大値などに置き換えられます。)
解決
拡張メソッドを書くことができます:
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0) return min;
else if(val.CompareTo(max) > 0) return max;
else return val;
}
編集:拡張メソッドは静的クラスに移動します - これは非常に低レベルの関数であるため、おそらくプロジェクトのコアネームスペースに移動する必要があります。その後、名前空間の使用指令を含むコードファイルのメソッドを使用できます。
using Core.ExtensionMethods
int i = 4.Clamp(1, 3);
.NET Core 2.0
.NET Core 2.0から始めます System.Math
今があります Clamp
代わりに使用できる方法:
using System;
int i = Math.Clamp(4, 1, 3);
他のヒント
試す:
public static int Clamp(int value, int min, int max)
{
return (value < min) ? min : (value > max) ? max : value;
}
使用するだけです Math.Min
と Math.Max
:
x = Math.Min(Math.Max(x, a), b);
ありませんが、作るのはそれほど難しくありません。ここで見つけました: クランプ
そうです:
public static T Clamp<T>(T value, T max, T min)
where T : System.IComparable<T> {
T result = value;
if (value.CompareTo(max) > 0)
result = max;
if (value.CompareTo(min) < 0)
result = min;
return result;
}
そして、それは次のように使用できます。
int i = Clamp(12, 10, 0); -> i == 10
double d = Clamp(4.5, 10.0, 0.0); -> d == 4.5
System.math namespaceにはありません
http://msdn.microsoft.com/en-us/library/system.math_members.aspx
XNAゲームスタジオで利用できるMathhelperクラスがあります。
http://msdn.microsoft.com/en-us/library/bb197892(v=xnagamestudio.31).aspx
共有するだけです リーの解決策 可能であれば、コメントの問題や懸念が扱われています。
public static T Clamped<T>(this T value, T min, T max) where T : IComparable<T> {
if (value == null) throw new ArgumentNullException(nameof(value), "is null.");
if (min == null) throw new ArgumentNullException(nameof(min), "is null.");
if (max == null) throw new ArgumentNullException(nameof(max), "is null.");
//If min <= max, clamp
if (min.CompareTo(max) <= 0) return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;
//If min > max, clamp on swapped min and max
return value.CompareTo(max) < 0 ? max : value.CompareTo(min) > 0 ? min : value;
}
違い:
- メソッド名は適切な動詞時制を使用します(
ed
)(さらに)値が内側に固定されていないことを示し、代わりに新しい値が返されることを示します(参照 @Jimbalterのコメント). - 適切です
null check
すべての入力について(参照してください @jeppestignielsenのコメント). - スワップ
min
とmax
もしもmin > max
(見る @jeppestignielsenのコメント).
制限:片側クランプはありません。もしも max
は NaN
, 、常に戻ります NaN
(見る ハーマンのコメント).
以前の回答を使用して、私は自分のニーズのために以下のコードに凝縮しました。また、これを使用すると、最小または最大でのみ数字をクランプできます。
public static class IComparableExtensions
{
public static T Clamped<T>(this T value, T min, T max)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value.ClampedMaximum(max);
}
public static T ClampedMinimum<T>(this T value, T min)
where T : IComparable<T>
{
return value.CompareTo(min) < 0 ? min : value;
}
public static T ClampedMaximum<T>(this T value, T max)
where T : IComparable<T>
{
return value.CompareTo(max) > 0 ? max : value;
}
}
以下のコードは、任意の順序で境界を指定することをサポートしています(つまり、 bound1 <= bound2
, 、 また bound2 <= bound1
)。線形方程式から計算されたクランプ値にこれが役立つことがわかりました(y=mx+b
)ラインの勾配が増加または減少する場合。
私は知っています:コードは構成されています 5つの超ugly条件発現演算子. 。事は、 できます, 、そして以下のテストでそれを証明します。必要に応じて、厳密に不必要な括弧を自由に追加してください。
他の数値タイプの他のオーバーロードを簡単に作成し、基本的にテストをコピー/貼り付けることができます。
警告:浮動小数点数を比較するのは簡単ではありません。このコードは実装していません double
堅牢に比較。フローティングポイント比較ライブラリを使用して、比較演算子の使用を置き換えます。
public static class MathExtensions
{
public static double Clamp(this double value, double bound1, double bound2)
{
return bound1 <= bound2 ? value <= bound1 ? bound1 : value >= bound2 ? bound2 : value : value <= bound2 ? bound2 : value >= bound1 ? bound1 : value;
}
}
Xunit/FluentAssertionsテスト:
public class MathExtensionsTests
{
[Theory]
[InlineData(0, 0, 0, 0)]
[InlineData(0, 0, 2, 0)]
[InlineData(-1, 0, 2, 0)]
[InlineData(1, 0, 2, 1)]
[InlineData(2, 0, 2, 2)]
[InlineData(3, 0, 2, 2)]
[InlineData(0, 2, 0, 0)]
[InlineData(-1, 2, 0, 0)]
[InlineData(1, 2, 0, 1)]
[InlineData(2, 2, 0, 2)]
[InlineData(3, 2, 0, 2)]
public void MustClamp(double value, double bound1, double bound2, double expectedValue)
{
value.Clamp(bound1, bound2).Should().Be(expectedValue);
}
}