Ищите метод .NET Math, который будет обнулять отрицательное целое число - PullRequest
22 голосов
/ 24 марта 2010

По концепции похож на Math.Abs ​​() - я ищу функцию, которая при получении положительного целого возвращает то же самое целое число. Если задано отрицательное значение, вернется ноль.

Итак:

f(3) = 3
f(0) = 0
f(-3) = 0

Да, это достаточно просто, чтобы писать самостоятельно, но мне интересно, если класс .NET Math уже имеет это встроенное или то же самое может быть достигнуто путем ловкого объединения нескольких вызовов Math. *?? 1006 *

Ответы [ 6 ]

65 голосов
/ 24 марта 2010

Это называется Math.Max:

Math.Max(0, x)
32 голосов
/ 24 марта 2010

Кажется, это то, что вы хотите, нет?

Math.Max(0, num);
14 голосов
/ 24 марта 2010

Я думаю

Math.Max(0, x)

это то, что вы хотите.

3 голосов
/ 07 марта 2019

Учитывая 32-разрядное целое число со знаком num, следующее выражение возвращает ноль, если оно отрицательное, или исходное неизмененное значение в противном случае:

(~num >> 31) & num

Эта операция иногда называется зажатие ; значения меньше нуля фиксируются до нуля.


Объяснение

Только положительные целые числа (и ноль) имеют 0 для их знакового бита , который является самым левым или "старшим значащим битом" (a.ka., " MSB * 1025) * "). Давайте рассмотрим 32-битный случай. Поскольку позиции битов нумеруются слева направо, начиная с 0, знаковый бит - «бит 31». Если перевернуть этот бит и затем распространить его на каждую из 31 позиции бита, вы получите результат, в котором:

  • для положительных значений и нуля, все биты установлены (0xFFFFFFFF, -1) или
  • для отрицательных значений все биты очищаются (0x00000000, 0).

Путем маскирования исходного значения с этим результатом вы обнулили значение, но только если оно изначально было отрицательным.

Примечания

  1. Поскольку & (поразрядно- AND) имеет очень низкий приоритет в C # , вам обычно придется заключать эти выражения в внешние скобки:

    ((~num >> 31) & num)
    
  2. Если num равно без знака (например, uint ui), вы должны использовать приведение, чтобы убедиться, что сдвиг подписан. Это называется вправо-арифметическим сдвигом , и это гарантирует, что MSB дублируется в каждую сдвинутую вправо позицию:

    ((int)~ui >> 31) & ui
    
  3. Для 64-битных значений сдвиг на 63 бита вместо 31:

    /* signed */     long v;      (~v >> 63) & v
    
    /* unsigned */   ulong ul;    ((long)~ul >> 63) & ul
    
  4. Как показано, вы должны использовать оператор ~ (поразрядно- NOT), чтобы перевернуть бит знака. Если вы попытаетесь использовать «унарный минус» -, вместо этого вы получите неправильный ответ для значения 0x80000000, поскольку это одно из двух целочисленных значений, на которое не влияет применение знака минус . (Другой - ноль, но в любом случае он работает правильно). С другой стороны, битовое значение - NOT гарантированно перебрасывает каждый бит любого / каждого значения.

  5. Если вы спешите, вот несколько проверенных методов расширения, готовых для копирования / вставки:

    public static int Clamp0(this int v) => v & ~v >> 31;
    
    public static long Clamp0(this long v) => v & ~v >> 63;
    


Узнайте больше о неразветвленном коде!

Этот пример кода, представленный выше, является одним из самых простых примеров с битами , который демонстрирует код без ветвей . Если вы с ним не знакомы, этот термин обычно относится к широкому спектру методов микрооптимизации, которые пытаются минимизировать условные переходы в пользовательском коде, чтобы уменьшить вероятность ошибочных прогнозов в конвейере ЦП.

3 голосов
/ 07 июня 2013

Math.Max ​​лучше, но без математики и в VB

(num >= 0) * -num
3 голосов
/ 24 марта 2010

Похоже, Math. Макс - это путь, но это тоже сработало бы ...;)

(num + Math.Abs(num)) / 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...