Як би АЛУ в мікропроцесорі відрізняти підписане число -7, яке позначається 1111, і число, яке не підписується 15, також позначається 1111?
Як би АЛУ в мікропроцесорі відрізняти підписане число -7, яке позначається 1111, і число, яке не підписується 15, також позначається 1111?
Відповіді:
Коротка і проста відповідь: це не так. Жоден сучасний основний процесор ISA не працює так, як ви думаєте.
Для процесора це просто трохи візерунка. Ви, програміст, відслідковувати, що означає цей шаблон біт.
Загалом, ISA не розрізняють різні типи даних, коли мова йде про зберігання. (Ігнорування реєстрів спеціального призначення, таких як плаваючі регістри в FPU.) Це просто безглуздий зразок бітів до процесора. Тим НЕ менше, ІСАС робити різні види інструкцій , які можуть інтерпретувати бітову комбінацію по - різному. Наприклад, арифметичні команди , такі як MUL
, DIV
, ADD
, SUB
інтерпретувати бітовий шаблон в якості якого - то числа, в той час як логічні команди , таких як AND
, OR
, XOR
інтерпретувати його як масив логічних значень. Отже, програміст (або автор перекладача чи компілятор, якщо ви використовуєте мову вищого рівня), вибираєте правильні вказівки.
Наприклад, можуть бути окремі інструкції для підписаних чи непідписаних номерів, наприклад. Деякі ISA також мають інструкції з арифметики з двійковими кодами.
Однак зауважте, що я написав "сучасний основний ISA" вище. Насправді існують не основні або історичні МСА, які працюють по-різному. Наприклад, як оригінальний 48-розрядний CISC ISA IBM AS / 400, так і поточний 64-бітний RISC ISA на основі POWER системи, що тепер називається IBM i, розрізняють покажчики та інші значення. Покажчики завжди позначені тегами, і вони включають інформацію про тип та управління правами. ЦП знає, є значення вказівником чи ні, і лише привілейоване ядро i / OS може вільно маніпулювати покажчиками. Користувацькі програми можуть маніпулювати лише вказівниками, якими вони володіють, щоб вказати на пам'ять, якою вони володіють, використовуючи невелику кількість безпечних інструкцій.
Були також деякі історичні проекти ISA, які включали принаймні деяку обмежену форму обізнаності про тип.
char
, що є 16-бітовим типом. Звичайно, у байт-коді Java досі немає непідписаних арифметичних інструкцій, оскільки будь-які char
значення автоматично переходять у int
(32-розрядний підпис) для арифметики.
Коротка версія: вона не знає. Немає способу сказати.
Якщо 1111
являє собою -7, то у вас є представлення значущої величини , де перший біт є знаком, а решта бітів - величиною. У цьому випадку арифметика є дещо складною, оскільки безпідписане додавання та підписане додавання використовують іншу логіку. Таким чином, ви, мабуть, мали б SADD
і UADD
опкод, і якщо ви виберете неправильний, ви отримаєте безглузді результати.
Однак частіше 1111
це -1, у тому, що називається поданням двох доповнень . У цьому випадку АЛУ просто не хвилює, чи підписані чи ненаписані цифри! Наприклад, візьмемо операцію 1110 + 0001
. У підписаній арифметиці це означає "-2 + 1", а результат повинен бути -1 ( 1111
). У непідписаній арифметиці це означає "14 + 1", а результат повинен бути 15 ( 1111
). Тож АЛУ не знає, хочете ви підписаний чи непідписаний результат, і це не хвилює. Це додаток просто виконує так, як якщо б воно не було підписане, і якщо ви хочете трактувати це як підписане ціле число після цього, це залежить від вас.
EDIT: Як Руслан і Даніель Шеплер цілком справедливо зазначають у коментарях, деяким операндам все ще потрібні окремі підписані та непідписані версії, навіть на машині з двома доповненнями. Додавання, віднімання, множення, рівність тощо - це добре працює, не знаючи, чи підписані числа чи ні. Але поділ і будь-які порівняння, що перевищують / менші, повинні мати окремі версії.
EDIT EDIT: Існують і деякі інші уявлення, такі як доповнення , але вони в основному більше не використовуються, тому вам не доведеться турбуватися про них.
<
<=
>=
>
вони відрізняються для операндів підписаних проти неподписаних, тоді як ==
і !=
підписні-агностичні.
Однією з найважливіших переваг математики з двома доповненнями, якою користуються всі сучасні архітектури, є те, що інструкції щодо додавання та віднімання точно однакові як для підписаних, так і для непідписаних операндів.
Багато процесорів навіть не мають інструкцій щодо множення, ділення чи модуля. Якщо це так, вони повинні мати окремі підписані та непідписані форми інструкції, і компілятор (або програміст на мові збірки) обирає відповідну.
Процесори, як правило, мають різні вказівки для порівняння, що підписуються чи не підписуються. Наприклад, x86 може слідувати за CMP
символом " JL
(Перейти, якщо менше"), якщо порівняння має бути підписане, або JB
(Перейти, якщо нижче), якщо порівняння має бути непідписаним. Знову ж, компілятор або програміст обрали б правильну інструкцію для типу даних.
Кілька інших інструкцій часто надходять у підписаних і неподписаних варіантах, таких як зсув правої сторони або завантаження значення в ширший регістр, з або без розширення знаків.
smulh
і umulh
повертають лише верхні біти множення та підписані та непідписані інструкції, які повернути результат у регістр удвічі ширше, ніж джерело операндів.
Це не так. Процесор покладається на набір інструкцій, щоб повідомити, який тип даних він шукає і куди надсилати. Нічого про 1s і 0s в самому операнді не може по суті сигналізувати ALU, чи є дані char, float, int, підписаними int і т. Д. Якщо цей 1111 збирається в електричну ланцюг, яка очікує доповнення 2s, це відбувається інтерпретувати як доповнення 2s.
char
апаратному рівні такого немає. Можливо, колись, ще в часи механічних телепринтерів. Але сьогодні, A char
- це лише кількість, що стосується обладнання. Причина, чому різні цифри відповідають різним формам літер на вашому екрані, полягає в тому, що ці числа використовуються для вибору різних растрових зображень або різних процедур малювання з великої таблиці (тобто з "шрифту").
Я хочу надати відповіді до вже зроблених відповідей:
У більшості інших відповідей зазначається, що в арифметиці подвійних доповнень результат однаковий для підписаних і неподписаних чисел:
-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
для виконання підписаного поділу.
Існують також різні "умовні" інструкції (умовні стрибки, встановлення біт-за умовою), а також інструкції щодо множення для арифметичної підписаної та неподписаної форми.