С++ переполнение сдвига влево для отрицательных чисел

Как показано ниже, в коде есть ошибка. Когда ввод a = -1, b = 1, в одной из строк есть ошибка времени выполнения. Не могли бы вы помочь мне понять, как (a & b) становится INT_MIN?

Насколько я понимаю, -1 представлен как 32-битный двоичный формат 0xFFFFFFFF, а 1 представлен как 32-битный формат 0x00000001, таким образом (-1 и 1) станет 0x00000001. И моя команда python также показывает результат «0b1». Почему он сообщает об ошибке INT_MIN?

int getSum(int a, int b) {
    while (b != 0) {
        int carry = (a & b) << 1;//BUG! left shift of negative value -2147483648
        a = a ^ b;
        b = carry;
    }

    return a;
}

Обновление: правильно ли определен сдвиг вправо для отрицательных чисел? Кажется, можно сдвигать вправо отрицательные числа, если они удовлетворяют приведенным ниже требованиям.

С cppreference.com,

For unsigned a and for signed a with nonnegative values, the value of a >> b is the integer part of a/2b . For negative a, the value of a >> b is implementation-defined (in most implementations, this performs arithmetic right shift, so that the result remains negative).

In any case, if the value of the right operand is negative or is greater or equal to the number of bits in the promoted left operand, the behavior is undefined.

Мы знаем, что существует более одного способа представления отрицательного числа в двоичном виде, а не только 0xFFFFFFFF en.wikipedia.org/wiki/Signed_number_representations.

Miguel 10.04.2019 16:41

обратите внимание, что XOR не создает больше битов, чем операндов, поэтому он никогда не может переполниться (за исключением, вероятно, систем с представлением ловушек) Может ли XOR двух целых чисел выйти за пределы?. INT_MIT находится в пределах диапазона int, поэтому это не переполнение.

phuclv 10.04.2019 17:47

Первый a & b - это 1, как вы говорите, но вы находитесь в цикле while, который обновляет значения a и b, ошибка возникает на более поздней итерации.

M.M 11.04.2019 00:14

для перестановки битов в C используется беззнаковые типы.

Antti Haapala 11.04.2019 06:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
4
2 673
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагая, что это C или C++, ваша ошибка связана с тем, что Сдвиг влево отрицательного значения является неопределенным поведением и смещение влево значения со знаком, так что оно становится больше, чем MAX_INT, также является неопределенным поведением.

Если вы проверите значения a и b при выполнении этой последовательности, вы получите:

-1 1
-2 2
-4 4
...
-1073741824 1073741824

На данный момент a&b == 1073741824. Но сдвинуть его влево на 1 — это то же самое, что умножить на 2, что даст 2147483648, что больше, чем INT_MAX.

Это неопределенное поведение. Система может сделать что угодно. Похоже, что в вашем случае это дало битовый сдвиг 0x80000000. В подписанном int это представляет INT_MIN. Таким образом, в следующий раз в цикле вы пытаетесь сдвинуть влево отрицательное число, что опять-таки является неопределенным поведением. Ваша система решила рассматривать это как исключение.

В общем, если вы выполняете битовые манипуляции, вам лучше всего использовать беззнаковые типы.

Большое спасибо! В этом случае, когда a = -1 и b = 1, как мы будем обрабатывать сдвиг влево? По сути, функция getSum() вычисляет a + b с помощью битовых манипуляций.

thinkdeep 11.04.2019 05:55

приведение к неподписанному.

AShelly 11.04.2019 21:06

Спасибо, а не могли бы вы объяснить немного подробнее?

thinkdeep 12.04.2019 17:47

Другие вопросы по теме