Есть ли встроенный класс для зажатых значений в C #? [Дубликат]

См. также:

для Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs. 80% 29.aspx

и GCC утверждают совместимость с компилятором Microsoft .:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking -Pragmas.html

В дополнение к предыдущим ответам, обратите внимание, что независимо от упаковки в C ++ нет гарантий-распоряжений-членов. Компиляторы могут (и, конечно же, делать) добавлять в структуру элементов виртуальной таблицы и базовых структур. Даже существование виртуальной таблицы не обеспечивается стандартом (реализация виртуального механизма не указана), и поэтому можно сделать вывод, что такая гарантия просто невозможна.

Я вполне уверен, что порядок членов является гарантировано в C, но я не стал бы рассчитывать на это, когда писал кросс-платформенную или кросс-компиляторную программу.

77
задан Amro 18 August 2013 в 09:46
поделиться

7 ответов

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

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

EDIT: методы расширения идут в статических классах - так как это довольно низкоуровневая функция, вероятно, это должно быть в каком-то основном пространстве имен в вашем проекте , Затем вы можете использовать этот метод в любом файле кода, который содержит директиву 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);
98
ответ дан sgtfrankieboy 19 August 2018 в 16:52
поделиться
  • 1
    Где бы я положил это и вызывается CompareTo медленнее, чем сравнение с & lt; (для интегральных типов)? – Danvil 21 April 2010 в 14:55
  • 2
    В статическом классе и в .NET framework (не уверенном в моно, компактном и т. Д.), Общий тип должен быть перекомпилирован для типа и CompareTo inlined, поэтому никакого снижения производительности. – Robert Fraser 21 April 2010 в 15:01
  • 3
    @Frasier Если это не очень чувствительный к ультрапроизводительности код, вы вряд ли достигнете значительного прироста производительности, сделав это. Наличие его общего, вероятно, более полезно, чем сохранение нескольких микросекунд. – MgSam 6 June 2013 в 05:36
  • 4
    Хорошая вещь о сдерживании версии generic IComparable заключается в отсутствии бокса. Это должно происходить очень быстро. Помните, что с double и float метод CompareTo соответствует полному порядку, где NaN меньше всех других значений, включая NegativeInfinity. Поэтому он не эквивалентен оператору <. Если вы использовали < с типом с плавающей точкой, вам также нужно будет рассмотреть, как относиться к NaN. Это не относится к другим числовым типам. – Jeppe Stig Nielsen 7 August 2013 в 21:05
  • 5
    Вам нужно будет рассмотреть, как лечить NaN в любом случае. Версия с < и > выводит NaN, а использование NaN для min или max эффективно сделает односторонний зажим. С CompareTo он всегда будет возвращать NaN, если max - NaN. – Herman 18 March 2014 в 12:12

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

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 19 August 2018 в 16:52
поделиться

Попробуйте:

public static int Clamp(int value, int min, int max)  
{  
    return (value < min) ? min : (value > max) ? max : value;  
}
23
ответ дан Jwosty 19 August 2018 в 16:52
поделиться
  • 1
    Нечитаемый, но хороший лайнер! – Larry 16 February 2016 в 16:09
  • 2
    @Larry, Как это нечитаемо? Отлично для меня; +1 – Post Self 29 August 2017 в 20:25
  • 3
    Тьфу! Эти уродливые лишние круглые скобки! Если вы будете злым гением с двойными тройными операторами, по крайней мере, сделайте это правильно и избавитесь от них! – XenoRo 1 October 2017 в 08:07
  • 4
    @XenoRo Те & quot; избыточные & quot; скобки являются тем, что делает его читаемым. – Clearer 11 May 2018 в 07:46
  • 5
    @Cleaner - 1) Если вы собираетесь читать, двойные тройники будут исключены, и вместо этого будут использоваться блоки IF. 2) Вы не получаете шутку, не так ли? XD – XenoRo 11 May 2018 в 20:55

В пространстве имен System.Math нет

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

Существует класс MathHelper, где он доступен для игровой студии XNA, если это то, что вы делаете:

http://msdn.microsoft.com/ ан-нас / библиотека / bb197892 (v = XNAGameStudio.31) .aspx

10
ответ дан kemiller2002 19 August 2018 в 16:52
поделиться
  • 1
    +1 для MathHelper, хотя я не думаю, что буду использовать его. – Paul Draper 30 October 2013 в 22:30

Нет ни одного, но его не так сложно сделать. Я нашел здесь: 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
18
ответ дан Peter Mortensen 19 August 2018 в 16:52
поделиться
  • 1
    Это означает int a0 = x > a ? x : a; return a0 < b ? a0 : b, который (хотя и дает правильные результаты) не совсем идеален. – Mr. Smith 24 April 2014 в 04:25
  • 2
    и почему так? – d7samurai 24 April 2014 в 11:14
  • 3
    Это решение лучше, чем принятое. Нет двусмысленности. – aggsol 16 January 2015 в 11:06
  • 4
    @ d7samurai Если мы знаем, что min & lt; = max, Math.Min(Math.Max(x, min), max) приводит к еще одному сравнению, чем необходимо, если x & lt; минимум – Jim Balter 15 September 2015 в 05:58
  • 5
    @CodeClown Это решение приводит к ненужному сравнению, когда value & gt; max, а инвертированный порядок аргументов приглашает (и практически гарантирует) ошибки. Я не знаю, какую двусмысленность, по вашему мнению, можно избежать. – Jim Balter 15 September 2015 в 06:05
  • 6
    @JimBalter, теоретически это правда. Если вы посмотрите, как обычно реализуется CompareTo (), принятый ответ может принимать до 6 сравнений. Я не знаю, хотя, если компилятор достаточно умен и вставляет CompareTo () и удаляет лишние сравнения. – quinmars 6 September 2016 в 21:41
  • 7
    Это хорошо для случаев, когда вам нужно сделать это только один раз, тогда вся новая функция для этого кажется излишним. – feos 30 November 2017 в 17:51

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

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 (см. комментарий Германа ).

2
ответ дан XenoRo 19 August 2018 в 16:52
поделиться
  • 1
    Другое ограничение - nameof не работает для C # 5 или ниже. – RoLYroLLs 24 July 2018 в 20:54
19
ответ дан Peter Mortensen 31 October 2018 в 03:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: