Почему брюшной пресс (0x80000000) == 0x80000000?

Я только что начал читать Восхищение Хакера, и оно определяет брюшной пресс (-231) как-231. Почему это?

Я попробовал printf("%x", abs(0x80000000)) в нескольких различных системах и я возвращаю 0x80000000 на всех них.

21
задан sigjuice 29 March 2010 в 15:34
поделиться

9 ответов

Для 32-битного типа данных не существует выражения + 2 ^ 31, потому что наибольшее число равно 2 ^ 31-1 ... подробнее о дополнении до двух ...

{{ 1}}
14
ответ дан 29 November 2019 в 06:15
поделиться

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

То есть (в .NET, но все еще применяется):

int.MaxValue + 1 == int.MinValue  // Due to overflow.

И

Math.Abs((long)int.MinValue) == (long)int.MaxValue + 1
10
ответ дан 29 November 2019 в 06:15
поделиться

На самом деле в C поведение не определено. Из стандарта C99, §7.20.6.1 / 2:

Функции abs , labs и llabs вычисляют абсолютное значение целого числа ] j . Если результат не может быть представлен, поведение не определено.

и его сноска:

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

42
ответ дан 29 November 2019 в 06:15
поделиться

Представление дополнительного числа до двух имеет самый старший бит как отрицательное число. 0x80000000 - это 1, за которой следует 31 ноль, первая 1 представляет -2 ^ 31, а не 2 ^ 31. Следовательно, невозможно представить 2 ^ 31, так как наивысшее положительное число равно 0x7FFFFFFF, то есть 0, за которым следует 31 единица, что равно 2 ^ 31-1.

abs (0x80000000) поэтому не определен в двух дополнениях, так как он слишком велик, из-за этого машина просто сдается и снова выдает 0x80000000. Обычно по крайней мере.

3
ответ дан 29 November 2019 в 06:15
поделиться

Я думаю, что способ abs - это сначала проверить знаковый бит числа. Если его очистить, ничего не делать, поскольку число уже равно + ve , иначе вернуть 2-дополнение числа. В вашем случае это число -ve , и нам нужно найти его 2-дополнение . Но дополнение до 2 0x80000000 оказывается самим 0x80000000 .

1
ответ дан 29 November 2019 в 06:15
поделиться

Это возвращается к тому, как хранятся числа.

Отрицательные числа хранятся с помощью двух дополнений. Алгоритм выглядит следующим образом...

Перевернуть все биты, затем добавить 1.

Используя восьмибитные числа для примера...

+0 = -0

00000000 -> 11111111, 11111111 + 1 = 100000000

(но из-за ограничения битов это становится 00000000).

AND...

-128 [aka -(2^7)] равно -(-128)

10000000 -> 01111111, 01111111 + 1 = 10000000

Надеюсь, это поможет.

3
ответ дан 29 November 2019 в 06:15
поделиться

Очевидно, что математически, |-231| это 231. Если у нас 32 бита для представления целых чисел, мы можем представить не более 232 чисел. Если мы хотим получить представление, симметричное относительно 0, нам нужно принять несколько решений.

Ниже, как и в вашем вопросе, я предполагаю, что ширина чисел 32 бита. Для 0 должен использоваться хотя бы один битовый шаблон. Таким образом, для остальных чисел у нас остается 232-1 или меньше битовых шаблонов. Это число нечетное, поэтому мы можем либо иметь представление, которое не совсем симметрично относительно нуля, либо одно число может быть представлено двумя разными представлениями.

  • Если мы используем представление знак-магнитуда, то старший бит представляет знак числа, а остальные биты - величину числа. В этой схеме 0x80000000 - это "отрицательный ноль" (т.е. ноль), а 0x000000 - "положительный ноль" или обычный ноль. В этой схеме самое положительное число - 0x7fffffff (2147483647), а самое отрицательное - 0xffffffff (-2147483647). Преимущество этой схемы в том, что ее легко "декодировать", и в том, что она симметрична. Недостаток этой схемы в том, что вычисление a + b, когда a и b имеют разные знаки, является особым случаем, и с ним нужно разбираться специально.
  • Если мы используем дополнение единицы, то старший бит по-прежнему представляет знак. У положительных чисел этот бит равен 0, а остальные биты составляют величину числа. Для отрицательных чисел вы просто инвертируете биты из представления соответствующего положительного числа (возьмите дополнение с длинной серией единиц - отсюда и название ones' complement). В этой схеме максимальное положительное число по-прежнему 0x7fffffff (2147483647), а максимальное отрицательное число 0x80000000 (-2147483647). У 0 снова два представления: положительный ноль - 0x000000, а отрицательный - 0xffffffff. Эта схема также имеет проблемы с вычислениями, связанными с отрицательными числами.
  • Если мы используем схему дополнения двойки, отрицательные числа получаются путем взятия представления дополнения единицы и добавления к нему 1. В этой схеме существует только один 0, а именно 0x000000. Самое положительное число - 0x7fffffff (2147483647), а самое отрицательное - 0x80000000 (-2147483648). В этом представлении присутствует асимметрия. Преимущество этой схемы в том, что не нужно иметь дело с особыми случаями для отрицательных чисел. Представление само позаботится о том, чтобы выдать правильный ответ, если результат не переполняется. По этой причине большинство современных аппаратных средств представляют целые числа в этом представлении.

В представлении с двумя дополнениями нет способа представить 231. На самом деле, если вы посмотрите в limits.h или аналогичный файл вашего компилятора, вы можете увидеть определение для INT_MIN в таком виде:

#define INT_MIN (-2147483647 - 1)

Это сделано вместо

#define INT_MIN -2147483648

потому что 2147483648 слишком велико, чтобы поместиться в int в 32-битном представлении с двумя дополнениями. К тому времени, когда унарный оператор минус "получает" число для работы, уже слишком поздно: переполнение уже произошло, и вы не можете его исправить.

Итак, отвечая на ваш первоначальный вопрос, абсолютное значение самого отрицательного числа в представлении с двумя дополнениями не может быть представлено в этой кодировке. Кроме того, из вышесказанного следует, что для перехода от отрицательного значения к положительному в представлении с двумя дополнениями нужно взять его дополнение к единицам, а затем добавить 1. Таким образом, для 0x80000000:

1000 0000 0000 0000 0000 0000 0000 0000   original number
0111 1111 1111 1111 1111 1111 1111 1111   ones' complement
1000 0000 0000 0000 0000 0000 0000 0000   + 1

вы получите исходное число.

8
ответ дан 29 November 2019 в 06:15
поделиться

0x8000 .. хранится как 10000 .... (двоичный). Это известно как дополнение до двух, что означает, что старший бит (тот, что слева) используется для хранения знака значения, а отрицательные значения сохраняются с отрицательным двоичным кодом - 1. Функция abs () теперь проверяет знаковый бит, видит, что он установлен, и вычисляет положительное значение.

  • Чтобы получить положительное значение, сначала инвертирует все биты в переменной, что дает 01111 ...
  • Затем добавляет 1, что снова дает 1000 ... 0x8000 ... мы начали с

Теперь это снова отрицательное число, которое нам не нужно, причина в переполнении, попробуйте число 0x9000 ... которое равно 10010. ..

  • инвертирование битов приводит к 01101 ... добавление единицы приводит к 01110 ...
  • , что составляет 0xE000 ... положительное число

С этим числом переполнение останавливается бит 0 справа

1
ответ дан 29 November 2019 в 06:15
поделиться

, потому что для выполнения этой операции используется команда neg.

В книге «Искусство программирования на ассемблере» они сказали вот что.

Если операнд равен нулю, его знак не меняется, хотя при этом снимается флаг переноса . Отрицание любого другого значения устанавливает флаг переноса. Отрицание байта , содержащего -128, слова, содержащего -32 768, или двойного слова, содержащего -2 147 483 648, не изменяет операнд, но устанавливает флаг переполнения . Neg всегда обновляет флаги A, S, P, и Z, как если бы вы использовали подинструкцию

источник: http://www.arl.wustl.edu /~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-313 Таким образом, он установит флаг переполнения и будет молчать. Вот почему.

0
ответ дан 29 November 2019 в 06:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: