Підписані та непідписані номери


17

Як би АЛУ в мікропроцесорі відрізняти підписане число -7, яке позначається 1111, і число, яке не підписується 15, також позначається 1111?


3
Дивіться відповідь на відповідне запитання: cs.stackexchange.com/a/30047/28999 . До речі, підписаний -7 не представлений як 1111. Це -1. Тоді, наприклад, 1111 - 0001 = 1110 як у підписаному, так і підписаному справі (-2 проти 14)
Альберт Хендрікс

2
@AlbertHendriks Справедливо кажучи, деякі старі комп'ютери використовують "представлення величини" (один біт знаків і біт магнітуди), і ми все ще використовуємо цей стиль, наприклад, для IEEE плаває. Вони просто не елегантні і з ними важко працювати порівняно з доповненням двох. n1
Драконіс

1
Основна відмінність полягає в тому, як поводяться більше операторів, що більше, ніж менше, і в тому, чи відповідає зміна правої зміни найвищим бітом. Коли ви насправді множите і ділите, результат той самий.
Роб-


2
@Rob Це не зовсім правильно. Додавання, віднімання та множення є однаковими між безпідписаним і доповненням подвійних - якщо припустити, що ваші входи та результати однакового розміру. Поділ не той самий 6/2 є 3, але -2/2 - -1. І багато процесорів мають інструкції щодо множення, де два входи мають однаковий розмір, але вихід має вдвічі більший розмір, і в цьому випадку без підпису та доповнення двійки не однакові.
kasperd

Відповіді:


14

Коротка і проста відповідь: це не так. Жоден сучасний основний процесор 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, які включали принаймні деяку обмежену форму обізнаності про тип.


Зауважте, що байт-код Java також вважається ISA. І це дуже хвилює типи даних ...
Джон Дворак

Байтовий код Java робить своєрідне підрахунок як ISA, в тому сенсі, що він реалізований у кремнії. Однак перевірка базового типу такого типу - це перевірка, яку виконує завантажувач класів, тому типи в основному можна ігнорувати під час виконання. І звичайно, у байт-коду Java в першу чергу немає неподписаних типів.
Псевдонім

@Pseudonym: Ну, технічно, це дійсно є char, що є 16-бітовим типом. Звичайно, у байт-коді Java досі немає непідписаних арифметичних інструкцій, оскільки будь-які charзначення автоматично переходять у int(32-розрядний підпис) для арифметики.
Ільмарі Каронен

42

Коротка версія: вона не знає. Немає способу сказати.

Якщо 1111являє собою -7, то у вас є представлення значущої величини , де перший біт є знаком, а решта бітів - величиною. У цьому випадку арифметика є дещо складною, оскільки безпідписане додавання та підписане додавання використовують іншу логіку. Таким чином, ви, мабуть, мали б SADDі UADDопкод, і якщо ви виберете неправильний, ви отримаєте безглузді результати.

Однак частіше 1111це -1, у тому, що називається поданням двох доповнень . У цьому випадку АЛУ просто не хвилює, чи підписані чи ненаписані цифри! Наприклад, візьмемо операцію 1110 + 0001. У підписаній арифметиці це означає "-2 + 1", а результат повинен бути -1 ( 1111). У непідписаній арифметиці це означає "14 + 1", а результат повинен бути 15 ( 1111). Тож АЛУ не знає, хочете ви підписаний чи непідписаний результат, і це не хвилює. Це додаток просто виконує так, як якщо б воно не було підписане, і якщо ви хочете трактувати це як підписане ціле число після цього, це залежить від вас.

EDIT: Як Руслан і Даніель Шеплер цілком справедливо зазначають у коментарях, деяким операндам все ще потрібні окремі підписані та непідписані версії, навіть на машині з двома доповненнями. Додавання, віднімання, множення, рівність тощо - це добре працює, не знаючи, чи підписані числа чи ні. Але поділ і будь-які порівняння, що перевищують / менші, повинні мати окремі версії.

EDIT EDIT: Існують і деякі інші уявлення, такі як доповнення , але вони в основному більше не використовуються, тому вам не доведеться турбуватися про них.


Ах, готча. Дякую за це :)
noorav

10
У двох представленнях доповнення двох арифметичні операції підписані-агностичні: додавання, віднімання та множення (з твором тієї ж довжини, що й операнди). Тільки поділ повинен по-різному оброблятися для підписаних операндів.
Руслан

4
Існує також порівняння: < <= >= >вони відрізняються для операндів підписаних проти неподписаних, тоді як ==і !=підписні-агностичні.
Даніель

Множення часто має підписані та неподписані різновиди: 0xFFFFFFFF * 0xFFFFFFFF є 0xFFFFFFFE00000001, якщо не підписано, і 0x0000000000000001, якщо його підписано. Такі процесори, як Intel, повертають результат у 2 регістри, а верхній реєстр відрізняється для підписаних та неподписаних. Нижній регістр - 1 в обох ситуаціях.
Руді Вельтуа

9

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

Багато процесорів навіть не мають інструкцій щодо множення, ділення чи модуля. Якщо це так, вони повинні мати окремі підписані та непідписані форми інструкції, і компілятор (або програміст на мові збірки) обирає відповідну.

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

Кілька інших інструкцій часто надходять у підписаних і неподписаних варіантах, таких як зсув правої сторони або завантаження значення в ширший регістр, з або без розширення знаків.


1
Навіть множення є однаковим для цілих чисел, які не підписуються та підписуються (доповнення двох) до тих пір, поки вам не потрібен результат, щоб мати більше бітів, ніж входи . Якщо ви робите щось на кшталт 8 × 8 → 16 біт (або 16 × 16 → 32 біт і т.д.), множення, однак вам потрібно підписати розширення входів (або проміжні результати) .
Ільмарі Каронен

@IlmariKaronen Це правда; ARM A32 / A64 - це набори інструкцій, які мають багато форм інструкції множення, включаючи знаки-агностичні множини-додати, які записують лише біти нижчого порядку, але також smulhі umulhповертають лише верхні біти множення та підписані та непідписані інструкції, які повернути результат у регістр удвічі ширше, ніж джерело операндів.
Девіслор

6

Це не так. Процесор покладається на набір інструкцій, щоб повідомити, який тип даних він шукає і куди надсилати. Нічого про 1s і 0s в самому операнді не може по суті сигналізувати ALU, чи є дані char, float, int, підписаними int і т. Д. Якщо цей 1111 збирається в електричну ланцюг, яка очікує доповнення 2s, це відбувається інтерпретувати як доповнення 2s.


На charапаратному рівні такого немає. Можливо, колись, ще в часи механічних телепринтерів. Але сьогодні, A 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для виконання підписаного поділу.

Існують також різні "умовні" інструкції (умовні стрибки, встановлення біт-за умовою), а також інструкції щодо множення для арифметичної підписаної та неподписаної форми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.