Двоичное добавление без переполнения в C / C ++ - PullRequest
0 голосов
/ 28 февраля 2012

Я знаю, что когда в C / C ++ происходит переполнение, нормальное поведение заключается в обходе.Например, INT_MAX+1 - это переполнение.

Можно ли изменить это поведение, чтобы двоичное добавление выполнялось как обычное добавление, и в конце операции добавления не было переноса?

Какой-то код, так что это имело бы смысл.По сути, это один бит (полный), он добавляется бит за битом в 32

int adder(int x, int y)
{
    int sum;
    for (int i = 0; i < 31; i++)
    {
        sum = x ^ y;
        int carry = x & y;
        x = sum;
        y = carry << 1;
    }

    return sum;
}

. Если я пытаюсь adder(INT_MAX, 1);, он фактически переполняется, хотя я не использую оператор +.

Спасибо!

Ответы [ 3 ]

4 голосов
/ 28 февраля 2012

Переполнение означает, что результат добавления будет превышать std::numeric_limits<int>::max() (еще в C дней мы использовали INT_MAX).Выполнение такого сложения приводит к неопределенному поведению.Машина может аварийно завершить работу и при этом соответствовать стандарту C ++.Хотя вы, скорее всего, получите INT_MIN в результате, на самом деле нет никакого преимущества в зависимости от какого-либо результата вообще.

Решение состоит в том, чтобы вместо сложения выполнить вычитание, чтобы предотвратить переполнение и возьмите специальный случай:

if ( number > std::numeric_limits< int >::max() - 1 ) { // ie number + 1 > max
    // fix things so "normal" math happens, in this case saturation.
} else {
    ++ number;
}

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

Редактировать: Чтобы просто выполнять математику, не беспокоясь о переполнении или обработкеСамостоятельно, используйте библиотеку bignum, такую ​​как GMP .Это довольно портативный и, как правило, лучший на любой платформе.Имеет интерфейсы C и C ++. не напишите свою собственную сборку.Результат будет непереносимым, неоптимальным, а интерфейс будет вашей ответственностью!

2 голосов
/ 28 февраля 2012

Нет, вы должны добавить их вручную для проверки переполнения.

1 голос
/ 28 февраля 2012

Что вы хотите, чтобы результат INT_MAX + 1 был? Вы можете вписать INT_MAX только в int, поэтому, если вы добавите один к нему, результат будет , а не , который будет на единицу больше. ( Редактировать: на распространенных платформах, таких как x86 , оно будет перенесено на самое большое отрицательное число: -(INT_MAX+1). Единственный способ получить большее число - это использовать большую переменную.

Если предположить, что int равен 4 байтам (как это типично для компиляторов x86), и вы выполняете инструкцию add (в 32-битном режиме), регистр назначения просто переполняется - он вне битов и не может содержать большее значение. Это ограничение оборудования.

Чтобы обойти это, вы можете вручную написать код или использовать целочисленную библиотеку размера aribitrarily, которая выполняет следующие действия:

  • Сначала выполните обычную add инструкцию для слов самого низкого порядка. Если происходит переполнение, устанавливается флаг переноса.
  • Для каждого слова все более высокого порядка используйте инструкцию adc, которая обычно добавляет два операнда, но учитывает значение флага переноса (как значение 1).

Вы можете увидеть это для 64-битного значения здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...