13

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

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

5 ответов5

35

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

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

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


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

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

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

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

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

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

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, обеспечивающей неограниченную точность (конечно, до тех пор, пока ваша память не заполнится) для целочисленных, рациональных операций и операций с плавающей запятой.

5

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

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

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

3

«32-разрядный» - это действительно способ категоризации процессоров, а не стандартное решение. 32-разрядный процессор обычно имеет 32-разрядные регистры общего назначения для работы.

Тем не менее, нет четкого требования, чтобы все в процессоре было выполнено в 32-битном режиме. Например, для «32-разрядного» компьютера не было ничего необычного в том, чтобы иметь 28-разрядную адресную шину, потому что аппаратное обеспечение было дешевле. По той же причине 64-битные компьютеры часто имеют только 40-битную или 48-битную шину памяти.

Арифметика с плавающей точкой - другое место, где размеры меняются. Многие 32-разрядные процессоры поддерживают 64-разрядные числа с плавающей запятой. Они сделали это, сохранив значения с плавающей запятой в специальных регистрах, которые были шире, чем регистры общего назначения. Чтобы сохранить одно из этих больших чисел с плавающей запятой в специальных регистрах, нужно сначала разбить число на два регистра общего назначения, а затем выполнить инструкцию, чтобы объединить их в число с плавающей точкой в специальных регистрах. Оказавшись в этих регистрах с плавающей запятой, значения будут обрабатываться как 64-разрядные числа с плавающей запятой, а не как пара 32-разрядных половин.

Упоминаемая вами 80-битная арифметика является частным случаем этого. Если вы работали с числами с плавающей запятой, вы знакомы с неточностью, которая возникает из-за проблем округления с плавающей запятой. Одно из решений для округления состоит в том, чтобы иметь больше битов точности, но тогда вам нужно хранить большие числа и заставлять разработчиков использовать необычно большие значения с плавающей запятой в памяти.

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

Мораль истории: такие категории, как «32-битные», всегда опаснее, когда вы углубляетесь в вещи!

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-битных регистров в сопроцессоре.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .