Как 80-битная с плавающей запятой может использоваться 32-битной системой? [Дубликат]

13

Поскольку 32-разрядная система не может управлять числом 2 ^ 33 (из-за очевидного 32-разрядного ограничения), как можно управлять 80-разрядным числом с плавающей запятой ?

Это должно требовать "80-бит" ...

markzzz
источник
8
Так же, как и 64-битное число с плавающей точкой. Он использует 3 или (2) 32-битные регистры. Так как 80-разрядное число с плавающей запятой даже не является стандартным размером, это фактически будет 96-разрядное число с использованием только 80-разрядного числа.
Ramhound
5
когда вы беспокоитесь о платформенности платформы, вы беспокоитесь о внутренней работе ЦП, как говорили другие, и о способе выполнения инструкций в системе. Числа IEEE754 обычно непосредственно обрабатываются в исполнительных блоках FPU вашего ЦП, тогда как 128-битное число потребует использования нескольких запрограммированных команд, чтобы они могли объединять значение значения, которое оценивает приложение. это оставляет обработку числа до заявления.
Фрэнк Томас
2
@ Ƭᴇcʜιᴇ007 Не совсем контратип этого одного. Этот вопрос больше касается разницы между числом и его текстовым / ASCII-представлением, хотя некоторые из этих ответов также могут решить эту проблему.
Боб
3
Практически на всех современных машинах с плавающей запятой обрабатывается отдельный процессор (хотя обычно на том же чипе, что и основной процессор). Все такие процессоры знают, как обрабатывать 80-битные (хотя некоторые делают это намного быстрее, чем другие). ( И «ширина» процессора в любом случае является фикцией. )
Даниэль Р Хикс
6
@Ramhound: Нет, 80 бит - это особенность 8087, и она использует 1 регистр FP. Это определенно не 96-битное число.
MSalters

Ответы:

35

Одно из значений 32-битного процессора состоит в том, что его регистры имеют ширину 32 бита. Это не означает, что он не может иметь дело, скажем, с 64-битными числами, просто он должен иметь дело с младшей 32-битной половиной сначала, а затем с верхней 32-битной половиной секунды. (Вот почему ЦП имеют флаг переноса .) Это медленнее, чем если бы ЦП мог просто загружать значения в более широкий 64-битный регистр, но все же возможно.

Таким образом, «разрядность» системы не обязательно ограничивает размер чисел, с которыми может работать программа, потому что вы всегда можете разбить операции, которые не вписываются в регистры ЦП, на несколько операций. Таким образом, он замедляет операции, потребляет больше памяти (если вам нужно использовать память как «блокнот») и усложняет программирование, но операции все еще возможны.

Однако ничего подобного не имеет значения, например, с 32-разрядными процессорами Intel и процессорами с плавающей запятой, поскольку часть процессора с плавающей запятой имеет свои собственные регистры, а их ширина составляет 80 бит. (В начале истории x86, возможность с плавающей запятой была отдельным чипом, она была интегрирована в CPU начиная с 80486DX.)


Ответ @ Breakthrough вдохновил меня добавить это.

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

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

Если ваш показатель степени слишком велик, у вас возникает переполнение с плавающей точкой, но вы не можете легко распространить его на другой регистр, поскольку показатель степени и мантисса связаны друг с другом.

Я мог бы быть неточным и ошибочным в отношении некоторых из них, но я верю, что это суть этого. (Эта статья в Википедии иллюстрирует вышесказанное более кратко.)

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

LawrenceC
источник
4
Все, что вы добавили из моего вдохновения, правильно, так что не беспокойтесь там :) Я должен упомянуть только один момент, хотя вы можете использовать встроенные инструкции CPU, где существует модуль с плавающей запятой, вы также можете выполнять операции с плавающей запятой в программном обеспечении (с эквивалентным побитовым значением) или целочисленные математические операции). Для расширения до этой точки, при наличии достаточного количества памяти, вы также можете иметь числа произвольной точности (в отличие от наших фиксированных 64-битных или 80-битных в данном случае) с использованием программных алгоритмов / библиотек (один из наиболее часто используемых - это GNU Multiple Precision библиотека ).
Прорыв
1
Nitpick: первый интегрированный процессор 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 , стек FPU x87 имеет встроенную поддержку 80-битных величин, в системах, где такая поддержка отсутствует (или процессоры не имеют блока с плавающей запятой полностью!), Эквивалентные вычисления / операции должны выполняться в программном обеспечении .

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

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

При наличии достаточного количества памяти можно также выполнять вычисления на числах произвольной (или «бесконечной» - в пределах реалистичных границ) точности, используя больше памяти, поскольку требуется большая точность. Одна из реализаций этого существует в библиотеке GNU Multiple Precision , обеспечивающей неограниченную точность (конечно, до тех пор, пока ваша память не заполнится) для целочисленных, рациональных операций и операций с плавающей запятой.

Прорвать
источник
2
Вы не упомянули самую важную деталь: FPU x87 на платформе x86 имеет регистры с плавающей запятой шириной 80 бит, поэтому его собственные вычисления на самом деле выполняются с плавающей запятой 80 бит, не нужно ничего эмулировать в программном обеспечении.
Маттео Италия
@MatteoItalia Я вижу это сейчас, спасибо. Я думал, что первоначальный вопрос требовал более общего обзора того, как можно выполнять операции над числами, превышающими размер слова процессора, а не конкретной реализацией расширенных 80-битных операций с плавающей запятой в x86 (также, почему мой пример был 90-битным вместо 80 ...). Я обновил ответ сейчас, чтобы лучше отразить это, спасибо за заголовки.
Прорыв
5

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

Подумайте о умножении. Вы можете знать свои таблицы умножения до 10x10, но у вас, вероятно, нет проблем с выполнением 123x321 на листе бумаги: вы просто разбиваете его на множество мелких проблем, умножаете отдельные цифры, заботитесь о переносе и т. Д.

Процессоры могут делать то же самое. В «старые времена» у вас было 8 битных процессоров, которые могли выполнять математику с плавающей запятой. Но они были оооочень.

Floris
источник
1
Они были медленными только после определенного момента. Вы можете написать «быстрые» операции с плавающей запятой, если ограничитесь определенной спецификацией.
Ramhound
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-битных регистров в сопроцессоре.

ShadSterling
источник