Почему -INT_MIN = INT_MIN в знаковом представлении с дополнением до двух?

Я до сих пор не нашел причины, по которой наименьшее отрицательное число со знаком не имеет эквивалентного положительного числа со знаком? Я имею в виду, что в трехзначном двоичном числе для простоты 100 равно -4? но у нас не может быть положительного 4 в подписанном формате, потому что мы не можем. Он переполняется. Итак, как мы узнаем, что двойное дополнение 1000 равно -4, 1000 0000 равно -128 и так далее? У нас нет исходного положительного числа


person Lews Therin    schedule 18.01.2012    source источник
comment
Потому что вам нужно считать 0. [-4, -1] содержит 4 числа, а [0,3] содержит 4 числа, всего 8, а 3-значные двоичные числа могут иметь 2 в степени 3 (= 8). комбинации.   -  person André Caron    schedule 19.01.2012
comment
Какие? Извините, я не понимаю ничего, что вы написали до 2 ^ 3 = 8 возможных комбинаций.   -  person Lews Therin    schedule 19.01.2012
comment
У вас есть 4 отрицательных числа, 3 положительных числа и 1 ноль. Итого 8!   -  person Mr Lister    schedule 19.01.2012
comment
[-4, -1] - это набор чисел -4, -3, -2 и -1. [0, + 3] - это набор чисел 0, 1, 2 и 3. Каждая из этих половин вашего общего интервала имеет 4 числа, то есть все 8 слотов, выделенных для вашего 3-битного представления.   -  person André Caron    schedule 19.01.2012
comment
Для записи это также обсуждалось в чате: chat.stackoverflow.com/transcript/message/2401301#2401301   -  person Flexo    schedule 19.01.2012


Ответы (7)


Один из способов подумать об этом заключается в том, что знаковый формат дополнения до двух работает, присваивая каждому биту степень двойки, а затем меняя знак последней степени двойки. Давайте посмотрим, например, на -4, который представлен как 100. Это означает, что значение равно

-1 x 2^2 + 0 x 2^1 + 0 x 2^0

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

 1 x 2^2 - 0 x 2^1 - 0 x 2^0

Обратите внимание, что это значение равно

 1 x 2^2 + 0 x 2^1 + 0 x 2^0

Другими словами, нормальное двоичное представление этого значения - 100. Однако здесь у нас проблемы, потому что мы используем представление дополнения до двух со знаком, что означает, что мы специально зарезервировали бит 4 как бит знака. Следовательно, когда мы пытаемся интерпретировать битовый шаблон 100 как трехбитовое знаковое значение с дополнением до двух, он возвращается идентично тому, с чего мы начали. Здесь не хватает битов.

В более общем случае, учитывая n битов, из которых первый является битом знака в представлении с дополнением до двух, попытка вычислить -1000 ... 00 вернет то же значение, потому что бит, необходимый для хранения большого положительного значения, имеет специальный значение, присвоенное ему.

Так зачем вообще это делать? Причина этого в том, что если у вас есть только n бит, вы не можете хранить значения от -2 n - 1 до 2 n - 1, потому что есть 2 n + 1 разных чисел здесь и только 2 ^ n различных битовых комбинаций. Таким образом, исключение наибольшего положительного числа позволяет хранить все различные числа в указанном битовом шаблоне.

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

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

person templatetypedef    schedule 18.01.2012
comment
Ах да, теперь я понимаю. Спасибо за такое красивое объяснение. - person Lews Therin; 19.01.2012

-INT_MIN - это целочисленное переполнение и неопределенное поведение в C.

-INT_MIN гарантированно будет равно INT_MIN только при переносе целого числа со знаком. Это можно включить с помощью gcc, например, с помощью параметра -fwrapv.

Компилятор обычно использует тот факт, что целочисленное переполнение является неопределенным поведением в C для выполнения некоторых оптимизаций. Использование подписанных целочисленных переполнений небезопасно.

Хорошо известный пример оптимизации компилятора:

#define ABS(x) ((x) > 0 ? (x) : -(x)) 

void foo(int x){  
    if (ABS(x) >= 0) {
        // some code
    }
}

большинство современных компиляторов (gcc, icc) с включенными параметрами оптимизации оптимизируют тест, полагаясь на тот факт, что -INT_MIN является неопределенным поведением.

person ouah    schedule 18.01.2012
comment
Если быть точным, -fwrapv - это правильный флаг, обеспечивающий циклический переход по модулю для целых чисел со знаком. -fno-strict-overflow не позволяет оптимизатору предполагать, что целочисленные переполнения никогда не происходят. - person nucleon; 09.03.2016
comment
@nucleon -fwrapv - правильный вариант, спасибо, я отредактировал свой ответ. - person ouah; 09.03.2016

A. Существует четное количество возможностей для n-значного двоичного числа, поэтому мы не можем представить один и тот же диапазон для положительных и отрицательных чисел.

Б. Мы хотим, чтобы каждое число, начинающееся с 1, было отрицательным, а каждое число, начинающееся с 0, было неотрицательным. (не наоборот, потому что мы хотим, чтобы одно и то же представляло положительное значение и ноль в подписанных и неподписанных. Из-за этого 0 находится в половине положительных значений, поэтому они имеют на одну позицию меньше.

person asaelr    schedule 18.01.2012

Альтернатива дополнение до двух имеет такое свойство, которое известно как одно дополнение.
В форме дополнения наименьшее возможное значение также имеет допустимую положительную форму.


Дополнение до единицы работает путем простого инвертирования всех битов в самом числе.
Например, мы знаем, что 0110 == 6 и в дополнении до единицы 1001 == -6. Используя дополнение до одного, у нас есть столько же положительных чисел, сколько отрицательных.

Но как насчет битового представления 1111? Просто взглянув на него, мы можем сказать, что это «отрицательная» форма нуля (0000 = 0; 1111 = -0), но такое число не имеет никакого смысла и несколько расточительно.

Вместо этого мы используем дополнение до двух, которое похоже на дополнение до одного, но после инвертирования битов мы добавляем единицу. Итак, если мы знаем, что 0110 = 6, то дополнение до единицы равно 1001, а дополнение до двух - 1001 + 1 == 1010. Используя дополнение до двух, у нас нет «отрицательного нуля», потому что это вызывает переполнение.

Другой способ взглянуть на это: «если установлен старший бит, то число отрицательное». Это означает, что положительный диапазон равен [0 .. 2^(bits - 1)], а отрицательный диапазон - все остальное. Количество положительных чисел такое же, как и отрицательных, но поскольку (в этом формате) ноль считается положительным, отрицательный диапазон сдвигается на единицу до [-1 .. (neg) 2^(bits - 1)].


Предположим, мы имеем дело с 3-битным числом со знаком в дополнении до двух. Это даст нам следующую таблицу:

BITS  VALUE
000       0
001       1
010       2
011       3

100      -4
101      -3
110      -2
111      -1

Вы можете видеть, что количество положительных чисел такое же, как и отрицательных, просто отрицательные числа не начинаются с 0, как положительный набор.

person Mr. Llama    schedule 18.01.2012
comment
Целые числа с дополнением до двух рассматривают крайний левый бит как значение, которое должно быть скопировано во все биты слева от него [для любого N вычтите 1 из значения, крайние правые N бит которого равны 0, а крайние правые N битов результата будут равны 1 ], поэтому -1 эквивалентно бесконечной последовательности единиц. Для дополнения единиц используется одно и то же значение для заполнения левой и правой сторон. Значения 0,1111 ... и ... 111.0 [бесконечно много единиц в любом случае] эквивалентны 1.0 и ... 110.111 ... соответственно [бесконечно много единиц с обеих сторон в последнем случае], но только два последних формы нормализованы. - person supercat; 19.05.2016

Отсутствующая цифра - 0. В математическом смысле 0 не является ни положительным, ни отрицательным. Но в двоичном смысле, поскольку 0 не имеет отрицательного бита, он считается положительным. Другими словами, если вы хотите от -128 до 128, не может быть 0.

person Chris Eberle    schedule 18.01.2012
comment
Но у нас есть 0, который представляет собой 000 -3-значное представление. Откуда -4? Поскольку мы не можем представить 4 как подписанные - person Lews Therin; 19.01.2012
comment
Посчитайте вместе со мной: 3 бита = 2 ^ 3 варианта = 8 возможных комбинаций. Вот они: -4, -3, -2, -1, 0, 1, 2, 3. Согласно моему ответу, здесь 4 положительных числа и 4 отрицательных числа. -4 в этом случае будет 111, а 3 будет 011. - person Chris Eberle; 19.01.2012
comment
Да, верно, я это вижу. Однако как 128 гарантирует, что у нас нет 0? Я знаю, что у нас не может быть 128, потому что это -128 из-за того, что MSB действует как отрицательный знак. - person Lews Therin; 19.01.2012
comment
@LewsTherin: вы не можете сделать это в двух дополнительных представлениях. Вы могли бы придумать другое представление, в котором не было 0. - person André Caron; 19.01.2012
comment
@LewsTherin - Я думаю, проблема в том, что вы думаете о числах как человек (т.е. как я могу представить концепцию -10, если у меня нет +10). Компьютеры этого не видят. Двоичное сопоставление с основанием 10 со знаком - ИСТИННАЯ КОНВЕНЦИЯ. С таким же успехом я мог бы сказать, что 000110111000 соответствует 42, а затем создать вокруг этого целую систему. Знак минус и десятичные числа добавляются обратно только после перевода. - person Chris Eberle; 19.01.2012
comment
Блин, я сейчас совсем запуталась. 111 это не -4 .. в каком случае ты говоришь о Крисе? @ AndréCaron Думаю, ты сможешь это сделать, но в этом нет никакого смысла, не так ли? Я пытаюсь понять ответ Криса о том, как наличие от -128 до 128 удаляет 0. - person Lews Therin; 19.01.2012
comment
@Chris только что увидел ваш ответ - это похоже на то, как мы выбираем представление 0 или 1 - как истинное или ложное. - person Lews Therin; 19.01.2012
comment
@ LewsTherin - Идея здесь в том, что в диапазоне от -128 до 128 есть 257 чисел, которые не могут уместиться в восемь бит (есть только 256 различных битовых шаблонов). Следовательно, необходимо исключить какое-то число из этого диапазона. Представление с дополнением до двух со знаком выбирает удаление максимально возможного значения (128), чтобы получить простую реализацию. - person templatetypedef; 19.01.2012
comment
Попробуйте это в качестве мысленного эксперимента: у вас есть 3 бита, что означает, что у вас есть 8 вариантов. Фактически, вы можете представить 8 любого числа, которое захотите. Таким образом, я мог бы сказать 000 = 56, 001 = 2, 010 = -83, 011 = 99, 100 = -422, 101 = 101, 110 = 23 и 111 = 10000. Самому компьютеру не нужно концептуализировать, что окончательное значение этих 8 бит действительно означает. Это зависит от программиста. То же самое и с двоичным кодом. На уровне ЦП это всего лишь биты. Тот факт, что позже это происходит очень хорошо обратно в числа с основанием 10, объясняется очень тщательным планированием. - person Chris Eberle; 19.01.2012
comment
@Chris Теперь я понимаю все основные моменты. То, что это просто соглашение - как программист выбирает определять значение ... но ваше утверждение, если вы хотите от -128 до 128, не могло быть 0. Меня сбивает с толку. Если бы вы могли уточнить, я был бы признателен, спасибо. РЕДАКТИРОВАТЬ: серьезно хочу, чтобы я мог выбрать более одного принятого ответа :( - person Lews Therin; 19.01.2012
comment
@LewsTherin мое заявление было немного поспешным. Более точное утверждение было бы, если бы там БЫЛО +128, вам нужно было бы опустить число в другом месте. Я выбрал 0, потому что это казалось абсурдным. Более реалистично вы, вероятно, понизите -128. - person Chris Eberle; 19.01.2012
comment
Итак, вы говорите, что мне пришлось бы отбросить число, чтобы количество знаков оставалось симметричным 4 положительным и отрицательным числам? - person Lews Therin; 19.01.2012
comment
Еще раз извините, это свойство симметрии требуется для арифметических целей? - person Lews Therin; 19.01.2012

Потому что вам нужно считать 0. Целочисленный диапазон [-4, -1] (или, что эквивалентно -4, -3, -2 и -1) содержит 4 числа, а остальная часть диапазона [0,3] (или, эквивалентно 0, 1, 2 и 3) содержит 4 числа, всего 8, а 3-значные двоичные числа имеют 2 в степени 3 (= 8) возможных комбинаций.

Подумайте об этом так. Любой диапазон целых чисел в форме [-n, + n] обязательно имеет нечетный размер (2 * n + 1 целое число). Какое бы целочисленное двоичное представление вы ни использовали, оно будет иметь разное количество отрицательных и положительных чисел, потому что количество комбинаций всегда четное (степени двойки).

person André Caron    schedule 18.01.2012

Итак, как мы узнаем, что двойное дополнение 1000 равно -4, 1000 0000 равно -128 и так далее? У нас нет исходного положительного числа

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

Процесс поиска двойного дополнения отрицательного числа:

Начните с обычного, не дополняющего два представления абсолютного значения числа, которое нужно представить. Итак, для -4 возьмем не двойное дополнительное представление | -4 |, 100.

Переверните все биты: 100 -> 011 (или ... 11111011 с бесконечным продолжением битов влево).

Добавьте один: 011 -> 100 (или ... 11111100)

Теперь усеките до количества используемых бит (это устраняет бит переноса или бесконечную строку единиц). В результате 100 - это 3-битное представление -4 с дополнением до двух.

Чтобы пойти другим путем, возьмите представление дополнения до двух (100), переверните биты (011) и добавьте единицу (100), и теперь у вас есть представление дополнения до двух | -4 |. 1 * 2 ^ 2 + 0 * 2 ^ 1 + 0 * 2 ^ 0 = 4. Следовательно, мы знаем, что представление, с которого мы начали, 100, является 3-битным представлением -4 с дополнением до двух.

person bames53    schedule 18.01.2012