Где я могу найти функцию «зажима» в .NET? - PullRequest
83 голосов
/ 21 апреля 2010

Я бы хотел зафиксировать значение x в диапазоне [a, b]:

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

Это довольно просто. Но я не вижу функции «зажим» в библиотеке классов - по крайней мере, не в System.Math.

(Для того, чтобы не «зажать» значение, необходимо убедиться, что оно лежит между некоторыми максимальными и минимальными значениями. Если оно больше максимального значения, его заменяют на максимальное и т.

Ответы [ 8 ]

116 голосов
/ 21 апреля 2010

Вы можете написать метод расширения:

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);
25 голосов
/ 15 июня 2010

Попробуйте:

public static int Clamp(int value, int min, int max)  
{  
    return (value < min) ? min : (value > max) ? max : value;  
}
23 голосов
/ 07 декабря 2013

Просто используйте Math.Min и Math.Max:

x = Math.Min(Math.Max(x, a), b);
13 голосов
/ 21 апреля 2010

Нет такого, но его не так уж сложно сделать. Я нашел один здесь: зажим

Это:

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
10 голосов
/ 21 апреля 2010

Нет ни одного в пространстве имен 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

3 голосов
/ 03 октября 2017

Просто делюсь Решением Ли с замечаниями и проблемами в комментариях, где это возможно:

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

Различия:

Ограничения: Нет односторонних зажимов.Если max равно NaN, всегда возвращается NaN (см. Комментарий Германа ).

0 голосов
/ 29 марта 2019

Приведенный ниже код поддерживает указание границ в любом порядке (т. Е. bound1 <= bound2 или bound2 <= bound1). Я нашел это полезным для значений зажима, рассчитанных по линейным уравнениям (y=mx+b), где наклон линии может увеличиваться или уменьшаться.

Я знаю: код состоит из пяти сверхъестественных операторов условных выражений . Дело в том, что работает , и тесты ниже подтверждают это. Не стесняйтесь добавлять строго ненужные скобки, если хотите.

Вы можете легко создавать другие перегрузки для других числовых типов и в основном копировать / вставлять тесты.

Предупреждение: сравнивать числа с плавающей запятой непросто. Этот код не обеспечивает надежного сравнения 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 голосов
/ 12 декабря 2017

Используя предыдущие ответы, я сократил его до приведенного ниже кода для своих нужд. Это также позволит вам фиксировать число только по его минимальному или максимальному значению.

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