Типы с фиксированной запятой
Десятичные типы с фиксированной запятой
Мы уже видели, как определять типы с плавающей запятой. Однако в некоторых приложениях плавающая запятая не подходит, например, ошибка округления при двоичной арифметики неприемлема или, оборудование не поддерживает инструкции с плавающей запятой. В языке Ада есть десятичные типы с фиксированной запятой, которые позволяют программисту указать требуемую десятичную точность (количество цифр), а также коэффициент масштабирования (степень десяти) и, необязательно, диапазон. Фактически, значения такого типа будут представлены как целые числа, неявно масштабированные с указанной степенью 10. Это полезно, например, для финансовых приложений.
Синтаксис простого десятичного типа с фиксированной запятой:
type <type-name> is delta <delta-value> digits <digits-value>;
В этом случае delta
и digits
будут использоваться компилятором
для вычисления диапазона значений.
Несколько атрибутов полезны при работе с десятичными типами:
Имя атрибута |
Значение |
---|---|
First |
Наименьшее значение типа |
Last |
Наибольшее значение типа |
Delta |
Значение минимального шага типа |
В приведенном ниже примере мы объявляем два типа данных: T3_D3
и T6_D3
. Для
обоих типов значение дельты одинаково: 0.001.
При запуске приложения мы видим, что значение дельты обоих типов
действительно одинаково: 0.001. Однако, поскольку T3_D3
ограничен 3
цифрами, его диапазон составляет от -0,999 до 0,999. Для T6_D3
мы
определили точность 6 цифр, поэтому диапазон от -999,999 до 999,999.
Аналогично определению типа с использованием синтаксиса диапазона
(range
),
поскольку у нас есть неявный диапазон, скомпилированный код будет
проверять, что переменные содержат значения, не выходящие за пределы
диапазона. Кроме того, если результат умножения или деления десятичных
типов с фиксированной запятой меньше, чем значение дельты, известное из
контекста, фактический результат будет равен нулю. Например:
В этом примере, результат операции 0.001 * 0.5 будет 0.0005. Ввиду
того, что это значение не может быть представленно типом T3_D3
ведь
его дельта равна 0.001, реальное значение которое получит переменная A
будет равно нулю. Однако, если тип имеет большую точность, то
точности арифметических операций будет достаточно, и значение
C
будет равно 0.000500.
Обычные типы с фиксированной запятой
Обычные типы с фиксированной запятой похожи на десятичные типы с
фиксированной запятой в том, что значения, по сути, являются
масштабированными целыми числами. Разница между ними заключается в
коэффициенте масштабирования: для десятичного типа с фиксированной
запятой масштабирование, явно заданное дельтой (delta
),
всегда является степенью десяти.
Напротив, для обычного типа с фиксированной запятой масштабирование
определяется значением small
для типа, которое получается из указанного
значения delta
и, по умолчанию, является степенью двойки.
Поэтому обычные типы с фиксированной запятой иногда называют двоичными типами
с фиксированной запятой.
Note
Обычные типы с фиксированной запятой можно рассматривать как более близкие к реальному представлению на машине, поскольку аппаратная поддержка десятичной арифметики с фиксированной запятой не получила широкого распространения (изменение масштаба в десять раз), в то время как обычные типы с фиксированной запятой доступных используют широко распространенные инструкций целочисленного сдвига.
Синтаксис обычного типа с фиксированной запятой:
type <type-name> is
delta <delta-value>
range <lower-bound> .. <upper-bound>;
По умолчанию компилятор выберет коэффициент масштабирования, или small
, то
есть степень 2, не превышающую <delta-value>.
Например, можно определить нормализованный диапазон между -1.0 и 1.0 следующим образом:
В этом примере мы определяем 32-разрядный тип данных с фиксированной запятой для нормализованного диапазона. При запуске приложения мы замечаем, что верхняя граница близка к единице, но не ровна. Это типичный эффект типов данных с фиксированной запятой - более подробную информацию можно найти в этом обсуждении Q формата. Мы также можем переписать этот код определения типа:
Мы также можем использовать любой другой диапазон. Например:
В этом примере мы определяем 16-разрядный тип с именем T_Inv_Trig
, который имеет
диапазон от −𝜋/2 до 𝜋/2.
Для типов с фиксированной запятой доступны все общепринятые операции. Например:
Как и ожидалось, R
содержит 0,75 после сложения A
и B
.
На самом деле язык является более гибким, чем показано в этих примерах, поскольку на практике обычно необходимо умножать или делить значения различных типов с фиксированной запятой и получать результат, который может быть третьего типа. Подробная информация выходит за рамки данного вводного курса.
Следует также отметить, что, хотя подробности также выходят за рамки
данного курса, можно явно указать значение small
для обычного типа с
фиксированной точкой. Это позволяет осуществлять недвоичное
масштабирование, например:
type Angle is
delta 1.0/3600.0
range 0.0 .. 360.0 - 1.0 / 3600.0;
for Angle'Small use Angle'Delta;