Подписанные и неподписанные числа

17

Как ALU в микропроцессоре различает число со знаком -7, обозначаемое 1111, и число без знака 15, обозначаемое также 1111?

noorav
источник
3
См. Ответ на соответствующий вопрос: cs.stackexchange.com/a/30047/28999 . Кстати, подписанный -7 не представлен как 1111. Это -1. Тогда, например, 1111 - 0001 = 1110 в случае как со
Альберт Хендрикс
2
@AlbertHendriks Справедливости ради, некоторые старые компьютеры используют «представление величины знака» (один знаковый бит и биты величины), и мы все еще используем этот стиль, например, для плавающих объектов IEEE. Они просто не элегантны и с ними тяжело работать по сравнению с двумя дополнениями. N-1
Драконис,
1
Основное различие заключается в том, как ведут себя операторы greatThan / lessThan, и соответствует ли сдвиг вправо старшим битом. Когда вы на самом деле умножаете и делите, результат один и тот же.
Роб
5
Возможный дубликат Как целые числа со
знаком
2
@Rob Это не совсем правильно. Сложение, вычитание и умножение одинаковы между беззнаковым и двойным дополнением - при условии, что ваши входы и выходы имеют одинаковый размер. Деление не равно 6/2 равно 3, но -2/2 равно -1. И многие процессоры имеют инструкции умножения, где два входа имеют одинаковый размер, но выходной сигнал в два раза больше, и в этом случае unsigned и дополнения twos также не одинаковы.
Касперд

Ответы:

14

Короткий и простой ответ: это не так. Ни один современный процессор ISA не работает так, как вы думаете.

Для процессора это всего лишь небольшая схема. Вы, программист, должны следить за тем, что означает этот битовый шаблон.

В целом, ISA не различают разные типы данных, когда речь идет о хранилище. (Игнорирование регистров специального назначения, таких как плавающие регистры в FPU.) Это просто бессмысленный набор битов для CPU. Тем не менее, ИСАС делать разные виды инструкций , которые могут интерпретировать битовую комбинацию по - разному. Например, арифметические команды , такие как MUL, DIV, ADD, SUBинтерпретировать битовый шаблон в качестве какого - то числа, в то время как логические команды , таких как AND, OR, XORинтерпретировать его как массив логических значений. Таким образом, программист (или автор интерпретатора или компилятора, если вы используете язык более высокого уровня) должен выбрать правильные инструкции.

Например, могут быть отдельные инструкции для чисел со знаком и без знака. Некоторые ISA также имеют инструкции по арифметике с двоично-десятичными знаками.

Тем не менее, обратите внимание, что я написал «современный основной ISA» выше. На самом деле существуют неосновные или исторические ISA, которые работают по-другому. Например, как исходная 48-разрядная CISC ISA в IBM AS / 400, так и текущая 64-разрядная RISC ISA на базе POWER системы, которая теперь называется IBM i, различают указатели и другие значения. Указатели всегда помечены и включают информацию о типе и управление правами. Процессор знает, является ли значение указателем или нет, и только привилегированное ядро ​​i / OS может свободно манипулировать указателями. Пользовательские приложения могут манипулировать только указателями, которые им принадлежат, чтобы указывать на свою память, используя небольшое количество безопасных инструкций.

Были также некоторые исторические проекты ISA, которые включали, по крайней мере, некоторую ограниченную форму понимания типа.

Йорг Миттаг
источник
Обратите внимание, что байт-код Java также считается ISA. И это в значительной степени заботится о типах данных ...
Джон Дворак
Байт-код Java выполняет своего рода ISA в том смысле, что он реализован в кремнии. Тем не менее, проверка базового типа этого типа - это проверка, выполняемая загрузчиком классов, поэтому типы могут в большинстве случаев игнорироваться во время выполнения. И, конечно же, байт-код Java не имеет неподписанных типов.
псевдоним
@Pseudonym: Ну, технически, это действительно есть char, что является 16-битным типом. Конечно, в байт-коде Java до сих пор нет беззнаковых арифметических инструкций, поскольку любые charзначения автоматически повышаются до int(32-разрядного со знаком) для арифметики.
Илмари
42

Короткая версия: он не знает. Там нет никакого способа сказать.

Если 1111представляет -7, то у вас есть представление величины знака , где первый бит является знаком, а остальные биты являются величиной. В этом случае арифметика несколько усложняется, так как при добавлении без знака и при добавлении со знаком используется другая логика. Таким образом, у вас, вероятно, есть код операции SADDи UADDкод, и если вы выберете неправильный код, вы получите бессмысленные результаты.

Чаще, тем не менее, 1111представляет -1, в том, что называется представлением с двумя дополнениями . В этом случае ALU просто не волнует, подписаны ли числа или нет! Например, давайте возьмем операцию 1110 + 0001. В знаковой арифметике это означает «-2 + 1», и результат должен быть -1 ( 1111). В арифметике без знака это означает «14 + 1», и результат должен быть 15 ( 1111). Таким образом, ALU не знает, хотите ли вы получить подписанный или неподписанный результат, и ему все равно. Он просто добавляет сложение так, как если бы оно было беззнаковым, и если вы хотите потом рассматривать это как целое число со знаком, это ваше дело.

РЕДАКТИРОВАТЬ: Как справедливо указывают Руслан и Даниэль Шеплер в комментариях, некоторые операнды все еще нуждаются в отдельных версиях с подписью и без знака, даже на машине с двумя дополнениями. Сложение, вычитание, умножение, равенство и т. Д. Все прекрасно работает, не зная, подписаны числа или нет. Но деление и любые сравнения больше / меньше чем должны иметь разные версии.

РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ: Существуют и другие представления, например, дополнения , но в основном они больше никогда не используются, поэтому вам не нужно беспокоиться о них.

Draconis
источник
Ах, понял. Спасибо за это :)
noorav
10
В представлении дополнения двух три арифметические операции не зависят от подписи: сложение, вычитание и умножение (с произведением той же длины, что и операнды). Только деление должно обрабатываться по-разному для подписанных операндов.
Руслан
4
Также есть сравнение: < <= >= >различаются для операндов ==со !=знаком и без знака, тогда как и являются независимыми от подписи.
Даниэль Шеплер
Умножение часто имеет подписанные и неподписанные варианты: 0xFFFFFFFF * 0xFFFFFFFF равно 0xFFFFFFFE00000001, если оно не подписано, и 0x0000000000000001, если оно подписано. Процессоры, такие как Intel, возвращают результат в 2 регистрах, а верхний регистр отличается для подписанного и неподписанного. Нижний регистр равен 1 в обеих ситуациях.
Руди
9

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

Многие процессоры даже не имеют команд умножения, деления или модуля. Если это так, у них должны быть отдельные подписанные и неподписанные формы инструкции, и компилятор (или программист на языке ассемблера) выбирает соответствующую.

Процессоры также обычно имеют разные инструкции для сравнения со знаком или без знака. Например, x86 может следовать CMPс JL(Перейти, если меньше чем), если сравнение должно быть подписано, или JB(Перейти, если ниже), если сравнение должно быть без знака. Опять же, компилятор или программист выберет правильную инструкцию для типа данных.

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

Davislor
источник
1
Четное умножение одинаково для целых чисел без знака и со знаком (с дополнением до двух), при условии, что вам не нужно, чтобы результат имел больше битов, чем входные . Однако если вы выполняете что-то вроде умножения 8 × 8 → 16 бит (или 16 × 16 → 32 бита и т. Д.), Вам необходимо подписать расширение входных данных (или промежуточных результатов) .
Илмари
@IlmariKaronen Это правда; ARM A32 / A64 - это наборы команд, которые имеют множество форм команды умножения, включая незнаковое умножение-сложение, которое записывает только биты младшего разряда, но также smulhи umulhкоторые возвращают только верхние биты умножения , а также инструкции со знаком и без знака, которые вернуть результат в регистр в два раза шире, чем исходные операнды.
Дэвислор
6

Это не так. Процессор полагается на набор инструкций, чтобы сообщить ему, на какой тип данных он смотрит и куда его отправлять. В самом операнде нет ничего о единицах и 0, которые по своей сути могли бы сигнализировать ALU, являются ли данные символами, числами с плавающей запятой, int, со знаком int и т. Д. Если этот 1111 собирается в электрическую цепь, ожидающую дополнения 2 с, он собирается быть интерпретированным как дополнение 2s.

Джей Спейделл
источник
Там нет такого понятия, как charна аппаратном уровне. Может быть, когда-то давно, во времена механических телепринтеров. Но сегодня аппаратное обеспечение - charэто просто число. Причина того, что разные цифры соответствуют разным буквенным формам на экране, заключается в том, что эти цифры используются для выбора разных растровых изображений или разных процедур рисования из большой таблицы (т. Е. Из «шрифта»).
Соломон Слоу
3

Я хотел бы добавить дополнение к уже сделанным ответам:

В большинстве других ответов отмечается, что в арифметике с двумя дополнениями результат одинаков для чисел со знаком и без знака:

-2 + 1 = -1     1110 + 0001 = 1111
14 + 1 = 15     1110 + 0001 = 1111

Однако есть исключения:

Division:
  -2 / 2 = -1     1110 / 0010 = 1111
  14 / 2 = 7      1110 / 0010 = 0111
Comparison:
  -2 < 2 = TRUE   1110 < 0010 = TRUE
  14 < 2 = FALSE  1110 < 0010 = FALSE
"Typical" (*) multiplication:
  -2 * 2 = -4     1110 * 0010 = 11111100
  14 * 2 = 28     1110 * 0010 = 00011100

(*) На многих процессорах результат умножения двух n-битных чисел имеет ширину (2 * n) битов.

Для таких операций процессоры имеют разные инструкции для знаковой и беззнаковой арифметики.

Это означает, что программист (или компилятор) должен использовать другие инструкции для арифметики со знаком и без знака.

Например, в процессоре x86 есть инструкция, названная divдля деления без знака, и инструкция, названная idivдля деления со знаком.

Существуют также различные «условные» инструкции (условные переходы, set-bit-on-condition), а также инструкции умножения для арифметики со знаком и без знака.

Мартин Розенау
источник