Отрицание -2147483648 невозможно в C / C ++? - PullRequest
5 голосов
/ 04 декабря 2011
#include <iostream>
#include <stdlib.h>

int main(int argc, char *argv[])
{

  int num=-2147483648;
  int positivenum=-num;
  int absval=abs(num);

  std::cout<<positivenum<<"\n";
  std::cout<<absval<<"\n";

  return 0;
}

Привет. Мне довольно любопытно, почему вывод приведенного выше кода

-2147483648
-2147483648

Теперь я знаю, что -2147483648 - это наименьшее представляемое число среди подписанных целых чисел (при условии int32 бита).Я бы предположил, что ответы на мусор можно получить только после того, как мы опустимся ниже этого числа.Но в этом случае +2147483648 IS покрывается 32-битной системой целых чисел.Так почему отрицательный ответ в обоих случаях?

Ответы [ 5 ]

15 голосов
/ 04 декабря 2011

Но в этом случае +2147483648 IS покрывается 32-битной системой целых чисел.

Не совсем правильно. Это только идет до +2147483647. Так что ваше предположение неверно.

Отрицание -2147483648 действительно даст 2147483648, но оно переполнится до -2147483648.

Кроме того, целочисленное переполнение со знаком является технически неопределенным поведением.

7 голосов
/ 04 декабря 2011

Значение - (- 2147483648) равно , а не возможно в 32-битном знаковом int.Диапазон 32-битного целого со знаком от –2147483648 до 2147483647

2 голосов
/ 04 декабря 2011

Аааа, но это не так ... помните 0, наибольшее число подписано на самом деле 2147483647

1 голос
/ 04 декабря 2011

Поскольку представление дополнения в 2 целых чисел со знаком не является симметричным, и минимальное 32-разрядное целое число со знаком равно -2147483648, а максимальное - +2147483647. То, что -2147483648 является его собственным аналогом так же, как 0 (в представлении дополнения 2 есть только один 0, нет отличных +0 и -0).

Вот некоторые объяснения.

Отрицательное число -X, когда оно представлено как дополнение N-бита 2, фактически представляется как число без знака, равное 2 N -X. Итак, для 32-битных целых чисел:
если X = 1, то -X = 2 32 - 1 = 4294967295
если X = 2147483647, то -X = 2 32 - 2147483647 = 2147483649
если X = 2147483648, то -X = 2 32 - 2147483648 = 2147483648
если X = -2147483648, то -X = 2 32 + 2147483648 = 2147483648 (потому что мы сохраняем только 32 младших бита)

Итак -2147483648 = +2147483648. Добро пожаловать в мир ценностей дополнения 2.

0 голосов
/ 08 марта 2019

Все предыдущие ответы указывали на то, что результатом является UB (неопределенное поведение), поскольку 2147483648 не является допустимым значением int32_t.И все мы знаем, что UB означает, что может случиться что угодно, включая выпадение демонов из носа.Вопрос в том, почему поведение cout выводит отрицательное значение, которое, по-видимому, является худшим значением, которое оно могло бы выбрать случайным образом?

Я попытаюсь обосновать его в системе дополнения до двух.Отрицание на процессоре - довольно сложная операция.Вы не можете сделать это за один шаг.Один из способов реализации отрицания, т. Е. int32_t positivenum = -num, состоит в том, чтобы выполнить инверсию битов с последующим добавлением 1, т. Е. int32_t positivenum = ~num + 1, где ~ - оператор побитового отрицания, а +1 - для исправления ошибки выключения на единицу.,Например, отрицание 0x00000000 равно 0xFFFFFFFF + 1, что составляет 0x00000000 (после пролонгации, что делает большинство процессоров).Вы можете убедиться, что это работает для большинства целых чисел ... за исключением 2147483648. 2147483648 хранится как 0x80000000 в дополнении к двум.Когда вы инвертируете и добавляете один, вы получаете

- (min)        = -(0x80000000)
               = ~(0x80000000) + 1
               =   0x7FFFFFFF  + 1
               =   0x80000000
               =   min

Так волшебно, унарный оператор -, работающий на min, возвращает вам min!

Одна вещь, которая неочевидно, что арифметика двухкомпонентных процессоров не имеет понятия положительных или отрицательных чисел!Он рассматривает все числа как неподписанные под капотом.Существует только одна схема сумматора и одна схема умножителя.Схема сумматора работает для положительных и отрицательных чисел, а схема умножителя работает для положительных и отрицательных чисел.

Пример: -1 * -1

 = -1         * -1
 = (cast both to uint32_t)
 = 0xFFFFFFFF * 0xFFFFFFFF
 = FFFFFFFE00000001         // if you do the result to 64 bit precision
 =       0x00000001         // after you truncate to 32 bit precision
 =                1

Единственный раз, когда вы заботитесь о подписанныхvs unsigned - для сравнения, например < или >.

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