В.Ш. Кауфман - Языки программирования - концепции и принципы (1990) (1160787), страница 25
Текст из файла (страница 25)
4.8.3. Классификация числовых данных
Начать естественно с разумной классификации числовых данных в
зависимости от характера расчетов. В Аде три категории числовых типов:
целые, вещественные плавающие и вещественные фиксированные. Для каждой
категории типов имеются свои средства объявления.
Целые типы предназначены для точных расчетов, вещественные - для
приближенных. При этом плавающие типы воплощают идею действий с
нормализованными числами, представленными с относительной погрешностью,
зависящей от количества значащих цифр, а фиксированные - идею действий с
ненормализованными числами, представленными с абсолютной погрешностью,
зависящей от положения десятичной точки.
Плавающие типы чаще встречаются в ЯП для числовых расчетов. Поэтому
ограничимся демонстрацией основной идеи управления расчетами на примере
плавающих типов Ады.
4.8.4. Зачем объявлять диапазон и точность
Оставим пока в стороне синтаксис и семантику соответствующих
объявлений. Ведь объявить диапазон и точность - дело относительно нехитрое.
А вот что делать, когда разрядная сетка или принятое в компьютере
представление чисел не соответствует объявлению типа. Важно понимать, что
объявление типа остается особенно полезным именно в такой ситуации.
Действительно, в худшем случае исполнитель получает всю информацию,
чтобы признать (и информировать пользователя), что он непригоден для такой
программы. Если объявленные требования к диапазону и точности критичны для
предлагаемых расчетов, то такой отказ, безусловно, предпочтительнее, чем
трата времени и усилий на заведомо ошибочные расчеты, да еще с риском
оставить пользователя в "счастливом" неведении. К тому же легко
автоматически или визуально выделить фрагменты программы, вызвавшие
непригодность исполнителя. Это помогает либо подобрать подходящий
исполнитель (автоматически, если доступна, например, неоднородная сеть
машин), либо изменить выделенные компоненты программы.
4.8.5. Единая модель числовых расчетов
Чтобы гарантировать надежность расчетов в любой среде, т.е. управлять
диапазоном и точностью на достаточно высоком уровне абстракции, пользователь
должен опираться на модель расчетов, единую для всех сред. Однако, стремясь
в первую очередь к переносимости программ, нельзя забывать про эффективность
конкретизации (вспомните принцип реальности абстракций). Другими словами,
единая модель расчетов должна быть гибкой (требовать от конкретных
реализаций минимума свойств и действий).
В Аде абстракция (единство) обеспечивается понятием модельных чисел, а
конкретизация (гибкость) - понятием допустимых чисел.
Совокупность модельных чисел каждого подтипа полностью фиксируется на
уровне, независимом от среды (т.е. определяется семантикой ЯП и применяемым
программистом объявлением).
Допустимые числа - это некоторое надмножество модельных чисел,
зависящее от конкретной реализации (расчитанной на конкретную целевую
среду).
Гибкость модели проявляется в том, что расчеты программируются и
оцениваются с помощью модельных чисел, а выполняются с допустимыми числами.
Из набора предопределенных числовых типов реализация имеет право
подобрать для заданного объявления числового типа такой (по возможности
минимальный) базовый тип допустимых чисел, которых удовлетворяет указанным
при объявлении ограничениям диапазона и точности.
Итак, с одной стороны, все реализации ориентированы на единую "систему
координат" - модельные числа; с другой стороны каждая реализация работает со
своими допустимыми числами.
Рассмотрим на примере управление диапазоном модельных чисел. Пусть
объявлен плавающий тип:
type скорость is digits 8; -- число значащих цифр (D) = 8
После ключевого слова digits указан спецификатор точности D (равный в
нашем случае восьми), определяющий диапазон модельных чисел типа "скорость"
по следующим единым для всех реализаций правилам.
Прежде всего необходимо вычислить количество В двоичных цифр,
обеспечивающих ту же относительную погрешность, что и D десятичных цифр. В
общем случае
В = целая_часть(D * ln(10)/ln(2) + 1)
т.е. приблизительно 3.3 двоичные цифры для представления одной десятичной. В
нашем случае
В = [ 8 * 3,3 + 1 ] = 27.
Диапазон модельных чисел определяется как совокупность всех (двоичных!)
чисел, представимых в виде
знак * мантисса * (2 ** порядок)
где знак - это +1 или -1, мантисса - правильная двоичная дробь, записанная
ровно B двоичными цифрами, первая из которых 1 (т.е. нормализованная дробь),
порядок - целое число между -4*B и +4*B.
Таким образом, с каждой спецификацией D связывается конечный набор
вещественных модельных чисел. При этом фиксируется не только количество цифр
в мантиссе, но и максимальный порядок. В нашем случае двоичный порядок равен
27 * 4 = 108.
Соответствующий десятичный порядок 4*D = 32. Чем больше порядок, тем "реже"
встречаются модельные числа - точность представления плавающих типов
относительна.
4.8.7. Допустимые числа
Как уже сказано, диапазон допустимых чисел - расширение диапазона
модельных - самое экономичное с точки зрения реализации. В принципе в нашем
случае в качестве допустимых чисел могут фигурировать, например, числа с 40-
разрядной мантиссой и 7-разрядным порядком. Так что для представления такого
диапазона допустимых чисел подойдет, например, 48-разрядное машинное слово.
На практике транслятор подберет в качестве базового для типа "скорость"
ближайший из предопределенных плавающих типов REAL, SHORT_REAL, LONG_REAL
или иной из плавающих типов, определяемый реализацией.
Уточнить диапазон и точность при объявлении производного типа,
числового подтипа или объекта можно, как обычно, с помощью ограничения.
Например,
type высота is new скорость range 0.0 .. 1.0E5 ;
(высота может меняться от нуля до десяти тысяч).
subtype высота_здания is высота range 0.0 .. 1.0E3 ;
высота_полета : высота digits 5 ;
(для переменной высота_полета допустимая точность меньше, чем в типе
"высота").
4.8.8. Управление операциями
Управление диапазоном и точностью для плавающих типов имеется во многих
ЯП. Однако этого мало для надежного и независимого от среды управления
расчетами, если программист лишен возможности на уровне модельных чисел
учитывать погрешности, вносимые предопределенными (т.е. элементарными
арифметическими) операциями. Такой возможности до Ады не предоставлял ни
один ЯП. Результаты всех предопределенных операций над допустимыми числами
определяются в Аде с помощью модельных чисел следующим единым для любой
среды способом.
Модельным интервалом называется любой интервал между модельными
числами. С каждым допустимым числом ассоциируется так называемый связанный
модельный интервал - это минимальный модельный интервал, к которому
принадлежит рассматриваемое число (для модельных чисел связанным интервалом
считается само модельное число!).
Основное требование к точности реализации предопределенных операций
(модельное ограничение) состоит в том, что результат операций над
допустимыми числами должен попадать в минимальный модельный интервал,
содержащий точные математические результаты рассматриваемой операции при
изменении аргументов операции в пределах их связанных интервалов.
Наглядно это можно представить следующим рисунком (рис.4.4)
модельный интервал аргумента
-------[-------]-------
/ \
/ \ Точные математические
/ \ результаты на границе
---I---------------I---- модельного интервала
I I
--[----I---------------I----]--
Допустимый интервал результата
||
Минимальный объемлющий модельный интервал
Рис. 4.4
Из этого рисунка видно, что значениями операций вещественных типов в
конкретных реализациях могут быть любые числа, обладающие модельным
интервалом, но отклонения результатов операций регламентированы модельным
ограничением.
Искусство программиста состоит теперь в том, чтобы гарантировать
надежность расчетов, подбирая диапазон и точность в соответствии с условиями
задачи.
При этом он не должен забывать, что при реализации излишний диапазон
или излишняя точность могут стоить дорого и по времени, и по памяти (а могут
и превысить возможности реализации). Короче говоря, нужно программировать
как можно ближе к нуждам решаемой задачи.
В Аде предусмотрено, что реализация может предоставлять несколько
предопределенных (именованных или анонимных) плавающих типов с различными
диапазонами и точностью расчетов.
Искусство автора компилятора проявляется в том, чтобы компилятор был в
состоянии подобрать подходящий предопределенный тип (в качестве допустимых
чисел) для любого (или почти любого) объявления типа (с оптимальными
затратами на расчеты при полной гарантии соответствия модельному
ограничению).
Обратите внимание, в Аде отдано явное предпочтение двоичным машинам
(ведь допустимые числа включают модельные, причем в соответствии с модельным
ограничением результат операции над модельным числом должен быть точным,
если математический результат оказывается модельным числом - для
элементарных(!) арифметических операций такое требование выполнимо, в
отличие от произвольных математических функций). К тому же не любым двоичным
машинам, а с достаточно большим порядком во встроенном представлении
плавающих чисел (ведь далеко не во всех машинах допустимы порядки, вчетверо
превышающие длину мантиссы; во всяком случае в БЭСМ-6 это не так).
4.9. Управление представлением
Суть проблемы. Единая модель числовых расчетов, как мы видели,
позволяет программисту непосредственно управлять представлением данных
числовых типов в целевой машине. Но потребность управлять представлением
возникает не только для числовых типов и не только для данных. Причем
требуется управлять в некотором смысле окончательным представлением (как и в
случае числовых типов), а не промежуточным (когда, например, данные
приватного типа мы представляли данными комбинированного типа). Другими
словами, требуется управлять представлением объектов в терминах понятий, в
общем случае выходящих за рамки машинно-независимого ЯП и определенных
только на конкретной целевой машине.
Такого рода потребность особенно часто возникает в системных
программах, вынужденных взаимодействовать, в частности, с нестандартными
устройствами обмена (ввода-вывода) или со средствами управления прерываниями
целевой машины. Например, требуется явно указать адрес, с которого
располагается реализация реакции на конкретное прерывание.
Конечно, программы, использующие управление окончательным (или, как
часто говорят, "абсолютным") представлением, перестают быть машинно-
независимыми. Однако это та мера зависимости от машины (та мера
конкретизации), без которой программа неработоспособна.
Вместе с тем это зависимость только от целевой машины. Сами средства
управления представлением данных могут оставаться нормальными конструктами
машинно-независимого ЯП, где они играют роль компонент общего аппарата
связывания, а именно связывания абстрактной спецификации данных с их
конкретным абсолютным представлением. Такое связывание выполняется при
трансляции и может быть выполнено на любой транслирующей (инструментальной)
машине.
С другой стороны, если связывание такого рода выделено как достаточно
общее языковое понятие и ему соответствует легко идентифицируемый конструкт,
то настройка программы (ее перенос) на другую целевую машину сводится к
изменению только таких конструктов.
Именно такой идеей и руководствовались авторы ЯП Ада. Управление
абсолютным представлением выделено в конструкт, который называется УКАЗАНИЕМ
ПРЕДСТАВЛЕНИЯ (спецификацией представления, representation clauses).
Указание представления должно следовать за объявлением тех сущностей,
представление которых в нем конкретизируется. В Аде можно указывать
представление для типов, объектов данных, подпрограмм, пакетов и задач, а
также для входов.
[Подход к языковым конструктам как компонентам единого аппарата
абстракции-конкретизации позволяет легко обнаружить перспективу развития
средств управления представлением в Аде. А именно, высшим уровнем оформления
абстракции представления было бы выделение специального программного
сегмента ("модуля представления"), предназначенного исключительно для
описания привязки машинно-независимых сегментов к конкретной целевой машине.
Вопросы. Что бы это дало? Каковы недостатки такого решения?
Интересно, что эта перспектива неоднократно рассматривалось автором на
лекциях за несколько лет до того, как ему стало известно о воплощении
модулей управления представлением в системе Кронус (новосибирской
модификации Модулы-2). Так что анализ ЯП с самых общих "философских" позиций
действительно позволяет иногда прогнозировать их развитие.]