Можно ли предотвратить целочисленное переполнение в C # с помощью беззнакового сдвига вправо? - PullRequest
6 голосов
/ 23 сентября 2008

Я хочу, чтобы AlwaysPositive был присвоен положительный номер со всеми возможными значениями для lareValue1 и largeValue2 (это как минимум 1).

Следующая инструкция вызывает переполнение буфера:

int alwaysPositive = (largeValue1 + largeValue2) / 2;

Я знаю, что могу предотвратить это, вычтя и добавив:

int alwaysPositive = largeValue1 + ((largeValue2 - largeValue1) / 2);

Но в других языках программирования я могу использовать беззнаковое смещение для достижения цели:

int alwaysPositive3 = (largeValue1 + largeValue2) >>> 1;

Как я могу сделать это в C #?


Ответы ниже всех решают проблему. Вероятно, есть много способов сделать это, но у всех них (включая мои решения) есть одна общая черта: все они выглядят запутанными.

Ответы [ 6 ]

3 голосов
/ 23 сентября 2008

unchecked((largeValue1 + largeValue2) >> 1) - это еще один вариант.

См. Документацию по ключевому слову unchecked .

3 голосов
/ 23 сентября 2008
int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + (largeValue1 & largeValue2 & 0x01);

Идея, лежащая в основе вышеизложенного, состоит в том, что если вы предварительно поделите результаты перед их добавлением, то вы избежите переполнения, поскольку оба старших бита будут сброшены. Затем вы добавляете небольшую логику коррекции, чтобы увеличить значение на единицу, если оба были положительными (округление вниз). Если вас волнует только одно из них (округление), вы можете изменить его на

int alwaysPositive = (largeValue1 >> 1) + (largeValue2 >> 1) + ((largeValue1 | largeValue2) & 0x01);
2 голосов
/ 23 сентября 2008

Вы можете сделать это так:

  x = largeValue1;
  y = largeValue2; 
  return (x&y)+((x^y)/2);

Это немного сложный способ получить среднее из двух целых чисел без переполнения.

Если вы хотите, вы можете заменить деление на два сдвигом битов, но компилятор сделает это за вас.

0 голосов
/ 23 сентября 2008
try
{
    checked { alwaysPositive3 = (largeValue1 + largeValue2); }
}
catch (OverflowException ex)
{
   // Corrective logic
}
0 голосов
/ 23 сентября 2008

Не слишком аккуратно, но вы имеете в виду «переполнение целых чисел», а не «переполнение буфера».

Я не знаю C #, так что может быть другой способ, но вы можете имитировать беззнаковое смещение, просто маскируя верхний бит: (x >> 1) & 0x80000000

0 голосов
/ 23 сентября 2008

Вы можете использовать uints:

uint alwaysPositive = (uint)(largeValue1 + largeValue2) / 2;
...