#binary #cpu-architecture #numeric #sign #twos-complement
#двоичный #cpu-архитектура #числовое #знак #двойки-дополнение
Вопрос:
-1 может быть представлено в 4-битном двоичном виде как (дополнение 2) 1111
15 также представлено как 1111.
Итак, как процессор различает значения от 15 до -1, когда он получает значения из памяти?
Ответ №1:
Процессору все равно, содержит ли байт -1 или 15, когда он перемещает его из одного места в другое. Не существует такого понятия, как «перемещение со знаком» (в местоположение того же размера — для большего или меньшего назначения есть перемещение со знаком).
Процессор заботится о представлении только тогда, когда он выполняет арифметику для байта. Процессор знает, выполнять ли арифметику со знаком или без знака в соответствии с операционным кодом, который вы (или компилятор от вашего имени) выбрали.
Комментарии:
1. Арифметика со знаком и без знака имеет значение только в случае дополнения 1. В дополнении 2 знак самоочевиден.
2.
11111111b 00000001b
, @amalantony: это переполняется, если обе величины не имеют знака (при условии 8-битных правил). Оно не переполняется, если они подписаны. Компилятор не может определить разницу, если у него где -то нет информации о типе (например, в коде операции или некоторых флагах)3. @Peter как система решает, является ли 15 (1111b) -1 = 14 и -1 (1111b) -1 (0001b) = -2
4. @amal: Подписанный или неподписанный имеет значение в представлении с двумя дополнениями. Набор команд, вероятно, будет предоставлять отдельные коды операций для сравнения со знаком и без знака, например. И компилятор C выдаст соответствующую инструкцию сравнения в зависимости от типов C (подписанных или неподписанных) операндов.
5. @MCG: Это был бы плохой пример, потому что 1111b — 0001b = 1110b, который можно интерпретировать как беззнаковый (15 — 1 = 14) или подписанный (-1 — 1 = -2) правильно. Однако для умножения и деления требуются разные инструкции для signed и unsigned.
Ответ №2:
В большинстве предыдущих ответов упоминались отдельные коды операций. Это может быть верно для более сложных операций, таких как умножение и деление, но для простого сложения и вычитания это не так, как работает процессор.
ЦП хранит данные о результате выполнения инструкции в своем регистре flags. На x86 (где я наиболее знаком) двумя наиболее важными флагами здесь являются флаги «переполнения» и «переноса».
По сути, процессору все равно, подписано ли число или нет, оно обрабатывает их одинаково. Флаг переноса устанавливается, когда число превышает наибольшее значение без знака, которое оно может содержать. Флаг переполнения устанавливается, когда он выходит за пределы или ниже диапазона числа без знака. Если вы работаете с числами без знака, вы проверяете флаг переноса и игнорируете флаг переполнения. Если вы работаете со знаковыми числами, вы проверяете флаг переполнения и игнорируете флаг переноса.
Вот несколько примеров:
Без знака:
1111 (15) 1111 (15) = 1110 (14)
Что вы делаете сейчас, так это проверяете флаг переноса, который в данном случае содержит тот, который дает конечный результат
1 1110 (30)
Подписано:
1111 (-1) 1111 (-1) = 1110 (-2)
В этом случае вы игнорируете флаг переноса, флаг переполнения должен быть установлен на ноль.
Без знака:
0111 (7) 0111 (7) = 1110 (14)
Когда вы проверяете флаг переноса, он должен быть равен нулю.
Подписано:
0111 (7) 0111 (7) = 1110 (-2)
В этом случае будет установлен флаг переполнения, означающий, что при добавлении произошла ошибка.
Итак, в итоге число подписывается или не подписывается только в зависимости от вашей интерпретации, процессор предоставляет вам инструменты, необходимые для их различения, но не различает само по себе.
Ответ №3:
Процессор не знает, является ли число подписанным или неподписанным. Когда компилятор создает файл машинного языка, он выбирает правильную операцию, которая будет выполнена, чтобы выполнить математическую операцию с этим числом. Например, если вы объявили, что ваша переменная имеет подписанный тип, то операция, выполняемая на машинном языке, будет такой, которая обрабатывает эту позицию памяти как значение со знаком.
В любом программном обеспечении любого типа всегда, когда вы интерпретируете данные, вы придаете им значение. Байт в памяти может быть числом со знаком или без знака, или символом, или частью музыкального файла, или пикселем на картинке и т.д. Что придает ему значение, так это то, как вы используете этот байт.
Ответ №4:
На уровне компилятора дифференцирование основано на типе данных. Если тип данных — int , то для этой переменной выделяется 4 байта (в C). Итак, 15 в дополнении 2 00000000 00000000 00000000 00000000 00001111
, а -1 11111111 11111111 11111111 11111111
. Затем компилятор преобразует это в соответствующий код операции процессора. ЦП выполняет этот код операции, и на этом уровне все имеет форму единиц и 0.
Комментарии:
1. Это не отвечает на вопрос, какое значение имеет процессор. Процессор не знает C.
2. Компилятор выделяет предопределенное количество байтов для каждого числа (независимо от языка, C был просто примером). Если двоичная версия состоит из всех единиц, то ее значение -1, если существует хотя бы 1 предшествующий бит 0, он интерпретируется как целое значение, отличное от 0. Вы его получили?
3. В связи с этим возникает вопрос, как процессор будет различать 32-разрядные значения -1 и 2 ^ 32 — 1, оба из которых имеют одинаковое битовое представление в двойном дополнении?
4. Нет. Вопрос в том, скажем, у меня есть
unsigned char i=255;
это11111111
в двоичном формате.11111111
будет -127 со знаком char . Процессор не имеет доступа к информации о типе из языка. Как он может определить, что есть что? (Я не говорю, что вопрос на самом деле является ответственным, поскольку он полностью зависит от фактического набора CPU / инструкций, просто говоря, что ваш ответ не отвечает на вопрос.)5. @amal что происходит, когда это 4-разрядная машина?
Ответ №5:
В дополнении 2 для представления 15 нам требуется 5 бит, диапазон для 2’complemnt составляет от -16 до 15, поэтому значение становится 01111, здесь бит MSB равен 0, поэтому его положительное значение для -1 станет 11111