Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Является ли смещение вправо неопределенным поведением для отрицательного числа в cpp и в java?

Автор вопроса: YvesОтветов: 3

Чтобы оптимизировать мой код cpp, в некоторых случаях я пытаюсь использовать смещение вправо. Вот пример:

int main()
{
    int i = (1 - 2) >> 31;  // sizeof(int) == 4
    ...
    ...
}

Я напечатал i и получил -1. Это означает, что он будет использовать 1 вместо 0 для заполнения пустой позиции, если число отрицательное. Другими словами, -1 >> 31 работает следующим образом:

1111...1    <--- the result of (1 - 2), which is -1
1111...1    <--- -1 >> 31, 1 is used to fill in the empty position

Я просто хочу знать, четко ли определено это поведение или нет?

Если это UB в cpp, то как насчет Java?

  • Возможный дубликат Смещается влево (‹‹) отрицательное целочисленное неопределенное поведение в C++11? user0042 01.08.2017
  • В Java определенно не undefined. >> делает расширение знака, >>> нет. См. Учебные руководства по Java™ - побитовые операторы и операторы побитового сдвига, или окончательный источник, спецификация языка Java, 15.19. Операторы сдвига. Andreas 01.08.2017
  • как насчет Java? - Зачем останавливаться на Java, спросите об этом также в C# и Rust. StoryTeller - Unslander Monica 01.08.2017

c++javac++17undefined-behavior

Ответы

Ответ 1 · рейтинг 1 · msc

Да. Это определяется реализацией.

Согласно C++03 5.8/3, который определяет сдвиг вправо:

Значение E1 >> E2 - это E1, сдвинутая вправо E2 битовых позиций. Если E1 имеет беззнаковый тип или если E1 имеет знаковый тип и неотрицательное значение, значение результата равно целой части частного E1, деленной на число 2, возведенное в степень E2. Если E1 имеет тип со знаком и отрицательное значение, результирующее значение определяется реализацией.

Для получения дополнительной информации см. этот ссылка.

Ответ 2 · рейтинг 1 · SAI ESWAR

По умолчанию он подписан int. Диапазон от -32767 до 32767, побитовый диапазон от -111111111111111 до +111111111111111. Самый первый бит слева действует как отрицательный или положительный индикатор. И все арифметические операции будут выполняться методом дополнения до 2. В общем, отрицательный int представлен в методе двух дополнений, т.е. возьмем пример того, как представлен -1.

4 Bytes = 32 bits
0000 0000 0000 0000 0000 0000 0000 0000
how represent 1
0000 0000 0000 0000 0000 0000 0000 0001
Then we invert the digits. 0 becomes 1, 1 becomes 0.
1111 1111 1111 1111 1111 1111 1111 1110
Then we add 1.
1111 1111 1111 1111 1111 1111 1111 1111
This is how -1 is represented

Сдвиг вправо отрицательного числа определяется как сдвиг на 1 с к старшим битовым позициям, тогда в дополнительном представлении на 2 с он будет вести себя как арифметический сдвиг - результат сдвига вправо на N будет таким же, как деление на 2N , округляя в сторону минус бесконечности. Таким образом, смещение -1 равно -1, теперь возьмите другое число. Например, если у вас есть 8-битное двоичное число с дополнением до 2, пусть оно представляет -3

    0000 0011
    Then we invert the digits.
    1111 1100
    Then we add 1.
    1111 1101

11111101, представляющее -3 в десятичном виде, и вы выполняете арифметический сдвиг вправо на 1, чтобы получить 11111110, представляющий -2 в десятичном виде, это то же самое, что и деление -3 на 2 ^ 1, что дает -1,5, которое округляется до отрицательной бесконечности, что приводит к -2 .

Ответ 3 · Andreas

В Java поведение >> четко определено для отрицательных чисел (см. ниже).

В C++ поведение >> не определено для отрицательных чисел (см. ответ от rsp а>).


Цитирование спецификации языка Java, §15.19. Операторы смены:

Значение n ›› с равно n сдвигу вправо с битовых позиций с расширением знака . Полученное значение равно floor(n / 2s). Для неотрицательных значений n это эквивалентно усечению целочисленного деления, вычисляемого оператором целочисленного деления /, на два в степени s.

Значение n ››› с равно n сдвигу вправо с битовых позиций с нулевым расширение, где:

  • Если n положительное, то результат будет таким же, как и у n ›› s.

  • Если n отрицательное и тип левого операнда int, то результат равен результату выражения (n ›› s) + (2 ‹‹ ~s) эм>.

  • Если n отрицательное и тип левого операнда long, то результат равен результату выражения (n ›› s) + (2L ‹‹ ~s) эм>.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы