Представление чисел с плавающей точкой

Практически любой язык программирования даёт возможность использовать в вычислениях дробные числа. Когда дело касается программной реализации численных методов или любых других вычислений на ЭВМ, важным вопросом является внутреннее представление чисел, с которым приходится работать программисту. От этого главным образом зависит точность вычислений,а также их скорость.

 

В этом отчёте будут рассматриваться те аспекты представления чисел в ЭВМ, которые важны пользователям, желающим активно работать с вещественными величинами. Вначале будут введены общепринятые понятия для дальнейшего изложения материала. Будет достаточно подробно рассмотрен наиболее часто используемый стандарт IEEE 754. В заключение будут приведены способы доступа к основным параметрам представления вещественных чисел в ряде компиляторов (Microsoft Visual Studio (2003,2005), Borland C (3.1), GCC(3.4) ).

Числа с плавающей точкой

 

Числа с плавающей точкой - общепринятая форма представления действительных чисел в ЭВМ. Основными параметрами такой формы представления является основание степени (base) и точность (precision). При этом всегда требуется, чтобы основание степени было целым чётным числом. Если и , то число 0.1 представляется в виде . Однако, очевидно, что при определённых параметрах некоторые числа не удастся представить точно. Например, при и то же самое число 0.1 представляется приблизительно в виде (поскольку в бинарном представлении число 0.1 имеет бесконечный вид).

 

В общем случае при заданных параметрах запись вида представляет число

 

При этом называется мантиссой числа и состоит из позиций. В дальнейшем под числом с плавающей точкой мы будем понимать действительные числа точно представимые в смысле данной формы.

 

Существуют ещё два важных параметра — максимальный и минимальный показатели степени и . Таким образом, при фиксированных параметрах мы можем представить разных чисел с учётом знака.

 

Здесь возникает проблема - что делать с числами, не представимыми точно. Чаще всего такая ситуация возникает при попытке представить числа, имеющие слишком длинное или вообще бесконечное представление (пример с 0.1). В этом случае нужное нам число лежит где-то между двумя числами с плавающей точкой и будет представляться одним из них. Реже встречается попытка использовать числа, меньшие чем , или большие чем . Подробнее об этих случаях речь пойдёт в разделе "Стандарт IEEE".

 

Введём ещё одну договорённость. Пока что представление чисел с плавающей точкой неуникально. Например, при и число 0.1 можно представить как и как . Представление числа, в старшей позиции которого стоит цифра, отличная от нуля , мы будем называть нормализованным. Использование нормализованных форм решает проблему неединственности представления чисел с плавающей точкой. (Однако, при такой договорённости возникает интересный вопрос — как представлять 0?)

Представление чисел с плавающей точкой - это представление числа с помощью двух других чисел: мантиссы (дробь от 0 до 0.999 ... ) и порядка, или характеристики (степень числа 10, на которую надо умножить мантиссу, чтобы получить исходное число).

 

Например, мантисса числа 64.5 - это число 0.645, а порядок - число 2, так как 64.5 = 0.645 Ч 102. Мантисса числа 0.0000012 - это число 0.12, а порядок - число -5, потому что 0.0000012 =0.12 Ч 10-5.

 

Операции над числами с плавающей точкой

 

Рассмотрим два числа с плавающей точкой: а Ч 10n и b Ч 10m. Произведение этих чисел равно (а Ч b) Ч 10n+m, а частное - (а/b)Ч 10n-m

 

Для сложения этих чисел требуется равенство п и m. При условии n = m сумма чисел равна (а + b) Ч 10n.

 

Задача. Найти сумму чисел А = 5.5 и В = -127.25

 

Решение. Найдем мантиссы и порядки этих чисел:

 

а) А = 5.5 = 101.12 = 0.10112 Ч 23 => мантисса равна 0.101101, порядок равен 3

 

б) В = -127.25 = -1111111.012 = -0.1111111012 Ч 27 => мантисса равна 0.111111101, порядок равен 7. Произведем выравнивание:

 

А= 0.00001011Ч 27

 

В = -0.111111101Ч 27

 

Получили два числа с одинаковым порядком.

Сложим их. А и В имеют разные знаки, поэтому сложение сводится к вычитанию. Так как абсолютное значение В больше абсолютного значения А, то вычитаем А из -В, а затем меняем знак.

 

-В : 0.111111101 порядок 7

 

А : -0.000010110 порядок 7

 

0.111100111 порядок 7

 

(-В) - А = 0.111100111Ч 27

А + В = -((-В) - А) = - 0.1111001112Ч 27

 

 

Проверка. А + В =-0.1111001112 27 = -1111001.11 = -121.75 = 5.5 + (-127.5) - верно.

 

Архитектура системы команд.

 

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

 

Двумя основными архитектурами набора команд, используемыми компьютерной промышленностью на современном этапе развития вычислительной техники являются архитектуры CISC и RISC. Основоположником CISC-архитектуры можно считать компанию IBM с ее базовой архитектурой /360, ядро которой используется с1964 года и дошло до наших дней, например, в таких современных мейнфреймах как IBM ES/9000.

 

Лидером в разработке микропроцессоров c полным набором команд (CISC - Complete Instruction Set Computer) считается компания Intel со своей серией x86 и Pentium. Эта архитектура является практическим стандартом для рынка микрокомпьютеров. Для CISC-процессоров характерно: сравнительно небольшое число регистров общего назначения; большое количество машинных команд, некоторые из которых нагружены семантически аналогично операторам высокоуровневых языков программирования и выполняются за много тактов; большое количество методов адресации; большое количество форматов команд различной разрядности; преобладание двухадресного формата команд; наличие команд обработки типа регистр-память.

 

Основой архитектуры современных рабочих станций и серверов является архитектура компьютера с сокращенным набором команд (RISC - Reduced Instruction Set Computer). Зачатки этой архитектуры уходят своими корнями к компьютерам CDC6600, разработчики которых (Торнтон, Крэй и др.) осознали важность упрощения набора команд для построения быстрых вычислительных машин. Эту традицию упрощения архитектуры С. Крэй с успехом применил при создании широко известной серии суперкомпьютеров компании Cray Research. Однако окончательно понятие RISC в современном его понимании сформировалось на базе трех исследовательских проектов компьютеров: процессора 801 компании IBM, процессора RISC университета Беркли и процессора MIPS Стенфордского университета.

 

Разработка экспериментального проекта компании IBM началась еще в конце 70-х годов, но его результаты никогда не публиковались и компьютер на его основе в промышленных масштабах не изготавливался. В 1980 году Д.Паттерсон со своими коллегами из Беркли начали свой проект и изготовили две машины, которые получили названия RISC-I и RISC-II. Главными идеями этих машин было отделение медленной памяти от высокоскоростных регистров и использование регистровых окон. В 1981году Дж.Хеннесси со своими коллегами опубликовал описание стенфордской машины MIPS, основным аспектом разработки которой была эффективная реализация конвейерной обработки посредством тщательного планирования компилятором его загрузки.

 

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

 

Среди других особенностей RISC-архитектур следует отметить наличие достаточно большого регистрового файла (в типовых RISC-процессорах реализуются 32 или большее число регистров по сравнению с 8 - 16 регистрами в CISC-архитектурах), что позволяет большему объему данных храниться в регистрах на процессорном кристалле большее время и упрощает работу компилятора по распределению регистров под переменные. Для обработки, как правило, используются трехадресные команды, что помимо упрощения дешифрации дает возможность сохранять большее число переменных в регистрах без их последующей перезагрузки.

 

Ко времени завершения университетских проектов (1983-1984 гг.) обозначился также прорыв в технологии изготовления сверхбольших интегральных схем. Простота архитектуры и ее эффективность, подтвержденная этими проектами, вызвали большой интерес в компьютерной индустрии и с 1986 года началась активная промышленная реализация архитектуры RISC. К настоящему времени эта архитектура прочно занимает лидирующие позиции на мировом компьютерном рынке рабочих станций и серверов.

 

Развитие архитектуры RISC в значительной степени определялось прогрессом в области создания оптимизирующих компиляторов. Именно современная техника компиляции позволяет эффективно использовать преимущества большего регистрового файла, конвейерной организации и большей скорости выполнения команд. Современные компиляторы используют также преимущества другой оптимизационной техники для повышения производительности, обычно применяемой в процессорах RISC: реализацию задержанных переходов и суперскалярной обработки, позволяющей в один и тот же момент времени выдавать на выполнение несколько команд.

 

Следует отметить, что в последних разработках компании Intel (имеется в виду Pentium P54C и процессор следующего поколения P6), а также ее последователей-конкурентов (AMD R5, Cyrix M1, NexGen Nx586 и др.) широко используются идеи, реализованные в RISC-микропроцессорах, так что многие различия между CISC и RISC стираются. Однако сложность архитектуры и системы команд x86 остается и является главным фактором, ограничивающим производительность процессоров на ее основе.