web-dev-qa-db-ja.com

.NETの「クランプ」機能はどこにありますか?

xを範囲[a, b]にクランプしたい:

x = (x < a) ? a : ((x > b) ? b : x);

これは非常に基本的なことです。しかし、クラスライブラリに関数「クランプ」はありません-少なくともSystem.Mathにはありません。

(「クランプ」を知らない場合、値は最大値と最小値の間にあることを確認します。最大値よりも大きい場合は、最大値などに置き換えられます)

84
Danvil

拡張メソッドを書くことができます:

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ディレクティブを含む任意のコードファイルでメソッドを使用できます。

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);
119
Lee

試してください:

public static int Clamp(int value, int min, int max)  
{  
    return (value < min) ? min : (value > max) ? max : value;  
}
25
Clit

Math.MinMath.Maxを使用するだけです:

x = Math.Min(Math.Max(x, a), b);
24
d7samurai

ありませんが、作るのはそれほど難しくありません。ここで見つけました: clamp

それは:

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
13
Jeremy B.

System.Math名前空間にはありません

http://msdn.Microsoft.com/en-us/library/system.math_members.aspx

MathHelperクラスがあり、それがXNAゲームスタジオで使用可能な場合に利用できます。

http://msdn.Microsoft.com/en-us/library/bb197892(v = XNAGameStudio.31).aspx

10
kemiller2002

Leeの解決策 可能な限りコメントの問題と懸念事項を共有します。

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;
}

違い:

制限:片側クランプはありません。 maxNaNの場合、常にNaNを返します( ハーマンのコメント を参照)。

3
XenoRo

以下のコードは、任意の順序での境界の指定をサポートしています(つまり、bound1 <= bound2、またはbound2 <= bound1)。これは、線形方程式(y=mx+b)線の勾配は増加または減少する場合があります。

私は知っています:コードは5つの非常にugい条件式演算子で構成されています。問題は、動作するであり、以下のテストがそれを証明しています。必要に応じて、不要な括弧を自由に追加してください。

他の数値型に対して他のオーバーロードを簡単に作成し、基本的にテストをコピー/貼り付けできます。

警告:浮動小数点数の比較は単純ではありません。このコードは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);
    }
}
0
NathanAldenSr

以前の回答を使用して、必要に応じて以下のコードに要約しました。これにより、最小または最大でのみ数値を固定することもできます。

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;
    }
}
0
Bobby Speirs