Почему отрицательные целые числа со знаком начинаются с наименьшего значения?
Я не могу объяснить этот вопрос одними словами (возможно, поэтому я не могу найти ответ), поэтому я постараюсь дать как можно больше подробностей. Это не совсем практический вопрос, мне просто любопытно.
Итак, скажем, у нас есть подписанный 8-битный Int.
sign | bytes | sign 0 | sign 1
? | 0000000 | (+)0 | (-)128
? | 1111111 | (+)127 | (-)1
Я не понимаю, почему это так работает, кто-то может объяснить? В моей голове имеет больше смысла, чтобы значение было одинаковым, а знак просто ставил плюс или минус вперед, поэтому для меня это выглядит задом наперед.
2 ответа
Есть пара систем для целых чисел со знаком.
Один из них, величина знака, это именно то, что вы ожидаете: часть, которая говорит, насколько велико число, и часть, которая либо оставляет число положительным, либо отрицает его. Это делает знаковый бит действительно особенным, существенно отличающимся от других битов. Например:
sign-magnitude representation
0_0000000 = 0
0_0000001 = 1
1_0000001 = -1
1_0000000 = -0
У этого есть некоторые неудобные побочные эффекты, в основном больше не соответствующие беззнаковой арифметике полезным способом (если вы добавляете два целых числа со знаком, как если бы они были беззнаковыми странными вещами, например, -0 + 1 = -1), что имеет далеко - достигающие последствия: все сложение / вычитание / равно / умножение требуют специальных версий со знаком, умножение и деление на степени два никоим образом не соответствуют сдвигам битов (кроме случайных), поскольку не имеет четкой корреляции с Z/2^k Z не сразу понятно, как он ведет себя алгебраически. Кроме того, -0 существует как отдельная вещь от 0, что странно и вызывает различные виды проблем в зависимости от вашей семантики, но никогда не вызывает проблем.
Наиболее распространенная система на сегодняшний день - это дополнение к двум, где знаковый бит не означает "раз 1 или раз -1", но "добавляет 0 или добавляет -2^k". Как и в случае с дополнением, знаковый бит в значительной степени является совершенно нормальным битом (за исключением деления и сдвига вправо). Например:
two's complement representation (8bit)
00000000 = 0 (no surprises there)
10000000 = -128
01111111 = 127
11111111 = -1 (= -128 + 127)
etc
Теперь обратите внимание, что 11111111 + 00000001 = 0 в 8-битной арифметике без знака в любом случае, и -1+1=0 явно желательно (на самом деле это определение -1). Таким образом, то, к чему это приводит, по крайней мере, для сложения / вычитания / умножения / сдвига влево, является простой старой арифметикой без знака - вы просто печатаете числа по-другому. Конечно, некоторые операторы все еще нуждаются в специальных подписанных версиях. Так как она так близко соответствует арифметике без знака, вы можете рассуждать о сложениях и умножениях, как будто вы находитесь в Z/2^k Z с полной уверенностью. Он имеет небольшую странность, сравнимую с существованием отрицательного нуля, а именно с наличием отрицательного числа без положительного абсолютного значения.
Идея сделать значение одинаковым и просто поставить плюс или минус впереди - известная идея, называемая представлением величины со знаком или аналогичным выражением. Обсуждение здесь говорит, что две главные проблемы с представлением величины со знаком состоят в том, что есть два нуля (плюс и минус), и что целочисленная арифметика становится более сложной в компьютерном алгоритме.
Популярной альтернативой для компьютеров является представление в виде двух дополнений, о чем вы и просите. Это представление упрощает арифметические алгоритмы, но выглядит странно, когда вы представляете, как вы делаете диаграмму двоичных значений вдоль числовой линии. Дополнение двух также имеет один ноль, который решает первую серьезную проблему.
Статья о представлении чисел со знаком в Википедии имеет таблицы сравнения, иллюстрирующие величину со знаком, дополнение к двум и три другие системы представления значений в строке десятичных чисел от -11 до +16 и в диаграмме двоичных значений от 0000 до 1111.