Як 32-розрядна система може використовувати 80-бітну плаваючу точку? [дублікат]


13

Оскільки 32-бітова система не може керувати числом 2 ^ 33 (оскільки очевидна 32-бітна межа), як можна керувати 80-бітним числом з плаваючою точкою ?

Він повинен вимагати "80-бітового" ...


8
Так само, як це робить 64-бітове число з плаваючою точкою. Він використовує 3 або (2) 32-бітні регістри. Оскільки 80-бітове число з плаваючою точкою навіть не є стандартним розміром, воно фактично буде 96-бітним числом, у якому використовуються лише 80-бітні.
Рамхаунд

5
коли ви турбуєтесь про кусання платформи, ви переживаєте про внутрішню роботу процесора, як говорили інші, і про те, як вказівки виконуються в системі. Номери IEEE754, як правило, безпосередньо обробляються у блоках виконання FPU вашого CPU, тоді як 128-бітове число вимагатиме використання декількох інструкцій, запрограмованих таким чином, щоб вони могли агрегувати значення значення, яке оцінює додаток. що залишає обробку номера до програми.
Френк Томас

2
@ Ƭᴇcʜιᴇ007 Не зовсім обман з цього . Це більше стосується різниці між числом та його текстом / представленням ASCII, хоча деякі з цих відповідей можуть також вирішити це питання.
Боб

3
Практично у всіх сучасних машинах плаваюча точка обробляється окремим процесором (хоча зазвичай на тому ж мікросхемі, що і основний процесор). Всі такі процесори знають, як поводитися з 80-бітними (хоча деякі роблять це набагато швидше, ніж інші). ( І "ширина" процесора так чи інакше є вигадкою. )
Даніель Р Хікс

6
@Ramhound: Ні, 80 біт - це особливість 8087, і він використовує 1 регістр FP. Це однозначно не 96-бітове число.
MSalters

Відповіді:


35

Одне із значень 32-бітного процесора полягає в тому, що його регістри мають 32 біти. Це не означає, що він не може мати справу з, скажімо, 64-бітовими числами, просто що він повинен мати справу з нижньою 32-бітовою половиною спочатку, а потім з верхньою 32-бітовою половиною секунди. (Тому CPU має прапор перенесення .) Це повільніше, ніж якби CPU міг просто завантажити значення в ширший 64-розрядний реєстр, але все-таки це можливо.

Таким чином, "розрядність" системи не обов'язково обмежує розмір чисел, з якими може мати справу програма, тому що ви завжди можете розбивати операції, які не вписуються в регістри процесора на кілька операцій. Так це робить операції повільнішими, споживає більше пам’яті (якщо вам доведеться використовувати пам’ять як «скретчпад»), і складніше програмувати, але операції все ж можливі.

Однак нічого з цього не стосується, наприклад, процесорів Intel 32 біт і плаваючої точки, оскільки частина процесора з плаваючою комою має власні регістри, і вони мають 80 біт шириною. (На початку історії x86 можливість з плаваючою комою була окремою мікросхемою, вона була інтегрована в процесор, починаючи з 80486DX.)


@ Відповідь прориву надихнула мене додати це.

Значення з плаваючою комою, наскільки вони зберігаються в регістрах FPU, працюють зовсім інакше, ніж двійкові цілі числа.

80 біт значення величини з плаваючою комою поділяються на мантісу та експонент (також існує "база" у числах з плаваючою комою, яка завжди дорівнює 2). Мантіса містить значущі цифри, і показник визначає, наскільки великі ці значущі цифри. Таким чином, немає "переповнення" в інший реєстр, якщо ваше число стає занадто великим, щоб вміститися в мантісі, ваш показник збільшується, і ви втрачаєте точність, тобто коли перетворите його на ціле число, ви втратите десяткові знаки справа від вас - тому його називають плаваючою точкою.

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

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

Це нормально, що це працює зовсім по-іншому, оскільки вся частина процесора з плаваючою комою є свого роду у власному світі - ви використовуєте спеціальні інструкції CPU для доступу до цього тощо. Крім того, до суті питання, тому що це окремо, біт FPU не є щільно поєднаний з розрядністю рідного процесора.


4
Все, що ви додали з мого натхнення, є правильним, тому нічого не турбуйте :) Лише один момент я повинен зазначити, хоча ви можете використовувати вбудовані вказівки процесора, де існує одиниця з плаваючою комою, але також можна виконувати операції з плаваючою комою в програмному забезпеченні (з еквівалентним розрядним розрядом або цілочисельні математичні операції). Щоб поширитись до цієї точки, маючи достатню кількість пам’яті, ви також можете мати довільні точні номери (на відміну від наших фіксованих 64-бітових або 80-бітних в цьому випадку), використовуючи програмні алгоритми / бібліотеки (однією з найбільш часто використовуваних є множинна точність GNU бібліотека ).
Прорив

1
Nitpick: перший інтегрований FPU від Intel був у 80486DX, а не в 80386.
spudone

2
@markzzz: Нічого не шалено, якщо це потрібно. Використання 16-бітових поплавців для імітації атомної бомби для того, щоб оцінити ваш ядерний запас, божевільне, оскільки це недостатньо точно, щоб ви були впевнені в результаті. У такому випадку потрібно 32 біт (і так, за старих часів ці обчислення проводилися на 16 бітових PDP). Аналогічно використання 32-бітових фолатів для імітації клімату недостатньо точне через хаотичний характер розрахунків.
slebetman

2
FWIW, загальний спосіб здійснення операцій з плаваючою комою на машинах без одиниць FP потрібного розміру - це робити це в програмному забезпеченні, використовуючи цілі інструкції. Тому що в кінці дня і показник, і мантіса числа плаваючої точки є просто цілими числами. Це те, як ми їх інтерпретуємо, надає їм особливого значення.
slebetman

2
@PTwr на x86 ви фактично маєте 7 корисних GPR для даних, включаючи EBP. Просто ABI більшості мовних реалізацій зберігає цей регістр для покажчика кадру стека. Але, наприклад, з GCC ви можете використовувати -fomit-frame-pointerдля повернення цього реєстру.
Руслан

13

32-розрядні, 64-бітні та 128-бітні всі відносять до довжини слова процесора, яку можна вважати "основним типом даних". Часто це кількість бітів, переданих в / з оперативної пам’яті системи, і ширина покажчиків (хоча ніщо не заважає використовувати програмне забезпечення для отримання більшої кількості оперативної пам’яті, ніж те, що може отримати доступ до одного вказівника).

Якщо припустити постійну тактову частоту (як і все інше в архітектурі, яка є постійною), і якщо припускати, що читання / запис пам'яті є однаковою швидкістю (ми припускаємо тут 1 тактовий цикл, але це далеко не так у реальному житті), ви можете додайте два 64-розрядних числа за один тактовий цикл на 64-бітній машині (три, якщо рахувати отримання чисел з ОЗУ):

ADDA [NUM1], [NUM2]
STAA [RESULT]

Ми також можемо робити те саме обчислення на 32-розрядній машині ... Однак на 32-розрядній машині нам це потрібно зробити в програмному забезпеченні, оскільки спочатку потрібно додати нижні 32-бітні компенсації переповнення, а потім додати верхні 64-бітні:

     ADDA [NUM1_LOWER], [NUM2_LOWER]
     STAA [RESULT_LOWER]
     CLRA          ; I'm assuming the condition flags are not modified by this.
     BRNO CMPS     ; Branch to CMPS if there was no overflow.
     ADDA #1       ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
     STAA [RESULT_UPPER]

Переглядаючи мій синтаксис складеної збірки, ви легко бачите, як операції з високою точністю можуть зайняти експоненціально довший час на машині з меншою довжиною слова. Це справжній ключ для 64-бітних і 128-бітних процесорів: вони дозволяють нам обробляти більшу кількість бітів за одну операцію. Деякі машини містять інструкції щодо додавання інших величин із перенесенням (наприклад, ADCна x86), але наведений вище приклад має на увазі довільні значення точності.


Тепер, щоб поширити це на питання, просто зрозуміти, як ми могли б додати числа, більші за наявні у нас регістри - ми просто розбиваємо проблему на шматки розмірів регістрів і працюємо звідти. Хоча як зазначає @MatteoItalia , стек F87 x87 має вбудовану підтримку 80-бітових величин, у системах, яким не вистачає цієї підтримки (або процесорам, у яких повністю не вистачає одиниці з плаваючою комою!), Еквівалентні обчислення / операції повинні виконуватися в програмному забезпеченні .

Отже, для 80-бітного числа після додавання кожного 32-розрядного сегмента також слід перевірити наявність переливу в 81-й біт і, можливо, нульовий біт вищого порядку. Ці перевірки / нулі виконуються автоматично для певних інструкцій x86 та x86-64, де вказані розміри вихідного та призначення операндів (хоча вони вказані лише в потужностях 2, починаючи з ширини 1 байт).

Звичайно, з числами з плаваючою комою не можна просто виконати двійкове додавання, оскільки мантіса та значні цифри упаковуються разом у зміщенному вигляді. В ALU на процесорі x86 є апаратна схема, яка виконує це для 32-розрядних і 64-розрядних поплавків IEEE; однак , навіть за відсутності блоку з плаваючою комою (FPU), однакові обчислення можуть проводитися в програмному забезпеченні (наприклад, за допомогою використання Наукової бібліотеки GNU , яка використовує FPU при компілюванні з архітектури, повертаючись до програмних алгоритмів якщо немає апаратного забезпечення з плаваючою комою (наприклад, для вбудованих мікроконтролерів, у яких відсутні FPU).

Враховуючи достатню кількість пам’яті, можна також виконувати обчислення за кількістю довільної (або «нескінченної» - в реалістичних межах) точності, використовуючи більше пам'яті, оскільки потрібна більша точність. Одна реалізація цього існує в бібліотеці множинної точності GNU , що дозволяє необмежену точність (звичайно, поки ваша ОЗУ не заповнена, звичайно) на цілі, раціональні та операції з плаваючою комою.


2
Ви не можете згадати найважливішу деталь: x87 FPU на платформі x86 має 80-бітові регістри з плаваючою точкою, тому його власні обчислення насправді робляться на 80 бітових поплавках, не потрібно нічого емулювати в програмному забезпеченні.
Маттео Італія

@MatteoItalia Я бачу це зараз, дякую. Я подумав, що в оригінальному запитанні було запропоновано більш загальний огляд того, як можна виконувати операції над номерами, більшими за розмір слова процесора, а не конкретною реалізацією розширених 80-бітових плаваючих файлів у x86 (також чому мій приклад складав 90 біт замість 80 ...). Я оновив відповідь зараз, щоб краще відобразити це, дякую за голову.
Прорив

5

Архітектура пам'яті системи може дозволяти вам переміщати 32 біти одночасно, але це не заважає використовувати більші числа.

Подумайте про множення. Можливо, ви знаєте свої таблиці множення розміром до 10x10, але ви, мабуть, не маєте проблем із виконанням 123x321 на папері: ви просто розбиєте його на безліч дрібних проблем, помноживши окремі цифри та піклуючись про перенесення тощо.

Процесори можуть робити те саме. У "старі часи" у вас були 8-бітні процесори, які могли робити математику з плаваючою комою. Але вони були slooooooow.


1
Вони були повільними лише після певного моменту. Ви можете записати "швидкі" операції з плаваючою точкою, якби ви обмежилися певною специфікацією.
Рамхаунд

3

"32-розрядна" - це дійсно спосіб категоризації процесорів, а не постановка на встановлення каменю. "32-бітний" процесор, як правило, має 32 бітні регістри загального призначення для роботи.

Однак у камені не встановлено вимоги, щоб все в процесорі було виконано в 32-розрядному. Наприклад, невідомо, що для "32-розрядного" комп'ютера мати 28-бітну шину адреси, оскільки це дешевше зробити апаратне забезпечення. 64-бітні комп'ютери часто мають лише 40-бітну або 48-бітну шину пам'яті з тієї ж причини.

Арифметика з плаваючою комою - ще одне місце, де розміри змінюються. Багато 32-бітних процесорів підтримували 64-бітні числа з плаваючою комою. Вони зробили це, зберігаючи значення плаваючої точки у спеціальних регістрах, які були ширшими, ніж регістри загального призначення. Щоб зберігати одне з цих великих чисел з плаваючою комою у спеціальних регістрах, слід спершу розділити число на два регістри загального призначення, а потім видавати інструкцію поєднувати їх у поплавок у спеціальних регістрах. Опинившись у цих регістрах з плаваючою точкою, значеннями будуть маніпулювати як 64-бітні плавці, а не як пара 32-бітних половинок.

80-бітна арифметика, яку ви згадуєте, є окремим випадком цього. Якщо ви працювали з числами з плаваючою комою, вам відома неточність, яка виникає внаслідок проблем із округленням плаваючої точки. Одне рішення для заокруглення - мати більше біт точності, але тоді вам доведеться зберігати більшу кількість і змушувати розробників використовувати в пам'яті незвично великі значення з плаваючою комою.

Рішення Intel полягає в тому, що регістри плаваючої точки - це 80 біт, але вказівки щодо переміщення значень до / з цих регістрів первинно працюють з 64-бітовими числами. Поки ви повністю працюєте в стеку з плаваючою крапкою Intel x87, всі ваші операції виконуються з 80 бітами точності. Якщо ваш код повинен витягнути одне з цих значень із регістрів плаваючої точки і зберегти його десь, він скорочує його до 64-біт.

Мораль історії: категоризації на кшталт "32-розрядні" завжди туманніші, коли заглиблюєшся в речі!


Але якщо я використовую 32-бітні значення плаваючої точки в 16-бітній системі (або 64-бітні значення плаваючої точки в 32-бітній системі), для цього потрібно лише більше пам'яті (оскільки вона повинна двічі реєструватися)? Або обробка інформації додасть накладні витрати, тому знадобиться більше часу?
markzzz

@markzzz: Робота з декількома регістрами майже завжди займає більше часу
Mooing Duck

Завантаження значення 32-бітової плаваючої точки в регістри спеціального призначення займе більше часу. Однак, як тільки вони зберігаються як 32-бітні плавучі в регістрах плаваючої точки спеціального призначення, апаратне забезпечення буде працювати на цих значеннях з плаваючою точкою на повній швидкості. Пам'ятайте, що "16-бітний" стосується лише розміру регістрів загальної мети. Реєстри з плаваючою комою мають спеціальні розміри для своєї задачі і можуть бути ширшими (у вашому випадку шириною 32 біти)
Cort Ammon,

2

"32-бітний" процесор - це той, де більшість регістрів даних - це 32-бітні регістри, і більшість інструкцій діють на даних цих 32-бітних регістрів. 32-бітний процесор також може одночасно передавати дані в 32-бітову пам'ять і з неї. Більшість регістрів 32-розрядні не означає, що всі регістри є 32-бітовими. Коротка відповідь полягає в тому, що 32-розрядний процесор може мати деякі функції, які використовують інші бітові рахунки, такі як 80-бітні регістри з плаваючою точкою та відповідні інструкції.

Як заявив @spudone у коментарі до відповіді @ ultrasawblade, першим процесором x86, який інтегрував операції з плаваючою комою, був Intel i486 (конкретно, 80486DX, але не 80486SX), який, відповідно до сторінки 15-1 мікропроцесорних програмістів i486 Довідковий посібник включає до своїх числових регістрів «Вісім індивідуально адресованих 80-бітних цифрових регістрів». I486 має 32-бітну шину пам'яті, тому для перенесення 80-бітного значення знадобиться 3 операції з пам'яттю.

У попередника покоління 486, i386, не було інтегрованих операцій з плаваючою комою. Натомість він мав підтримку використання зовнішнього плаваючого пункту "співпроцесор" 80387. Цей копроцесор мав майже таку ж функціональність, що була вбудована в i486, як ви бачите на сторінці 2-1 Посібника з програміста 80387 .

80-бітний формат з плаваючою точкою, схоже, зародився з 8087, математичним співпроцесором для 8086 і 8088. 8086 і 8088 були 16-бітними процесорами (з 16-бітною і 8-бітовою шиною пам'яті), і все ще були в змозі використовувати 80-бітний формат з плаваючою точкою, скориставшись 80-бітовими регістрами у співпроцесорі.

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