Подтвердить что ты не робот

Почему abs (0x80000000) == 0x80000000?

Я только начал читать Hacker Delight и он определяет abs (-2 31) как -2 31. Почему это?

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

4b9b3361

Ответ 1

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

Ответ 2

Собственно, в C поведение undefined. Из стандарта C99, §7.20.6.1/2:

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

и его сноска:

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

Ответ 3

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

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

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

и

Math.Abs((long)int.MinValue) == (long)int.MaxValue + 1

Ответ 4

Очевидно, математически, | & minus; 2 31 | 2 31. Если у нас есть 32 бита для представления целых чисел, мы можем представить не более 2 32 чисел. Если мы хотим, чтобы представление было симметричным относительно 0, мы должны принять несколько решений.

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

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

В двух дополнительных представлениях нет возможности представить 2 31. Фактически, если вы посмотрите на свой компилятор 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

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

Ответ 5

Это относится к тому, как сохраняются числа.

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

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

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

+0 = -0

00000000 → 11111111, 11111111 + 1 = 100000000

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

и...

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

10000000 → 01111111, 01111111 + 1 = 10000000

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

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

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

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

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

Ответ 9

потому что для выполнения этой операции используется команда 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 Поэтому он установит флаг переполнения и будет молча. Это причина.