Для решения задач по данной теме достаточно школьного курса математики и понимания дробей. Однако для более глубокого понимания материала приведу некоторую дополнительную информацию.
Вещественные числа (иногда их называют действительные числа) - это числа вида 0.1, 0.04, -10.9 и т.д. (т.е. они содержат дробную часть).
Вещественные числа в Аде можно отнести к плавающим типам либо к фиксированным типам.
Плавающие типы:
Вещественные типы с плавающей точкой имеют неограниченный диапазон значений и точность, определяемую количеством десятичных цифр после запятой (далее по тексту эта точность будет обозначаться буквой D).
В общем виде синтаксис плавающих чисел выглядит так (в квадратных скобках приведены необязательные значения):
[знак] целое.целое [E порядок] -- 3.5, 3.5E-1 |
Запись 3.5E-1 означает 3.5 * 10 ** (-1), т.е. 3.5 умноженное на 10 в степени -1, т.е. 0.35
В наших программах мы будем пользоваться записями попроще (0.35, 2.15 и т.д.). Но указанная запись считается основной. Обращаю Ваше внимание, что для разделения целой и дробной частей используется точка, а не запятая.
В языке Ада существуют предопределённые плавающие типы, например, Float (GNAT также предоставляет типы Long_Float и Long_Long_Float).
Для ввода-вывода переменных типа Float используется пакет Ada.Float_Text_IO:
with Ada.Float_Text_IO; use Ada.Float_Text_IO; with Ada.Text_IO; use Ada.Text_IO; --для New_Line procedure main is begin Put(Float'First); New_Line; Put(Float'Last); end main; |
Общее описание плавающего типа (в квадратных скобках приведены необязательные элементы):
type Т is digits D [range L .. R];
- T - Это имя создаваемого типа.
- Число D — минимальное требуемое число десятичных цифр (значащих) после точки. Это число должно быть обязательно целым числом и быть больше 0. Следует учесть один момент: если, например, D будет равно 8, то для обеспечения такой точности будет достаточно 38 разрядов, однако для архитектуры x32 такая точность невыполнима и программа станет непереносимой между платформами.
- Значения L и R называются соответственно нижней границей и верхней границей диапазона.
Предопределенный вещественный тип с плавающей точкой Float обеспечивает точность в шесть десятичных цифр после запятой:
type Float is digits 6 range -16#0.FFFF_FF#E+32 .. 16#0.FFFF_FF#E+32; -- -3.40282E+38..3.40282E+38 |
Здесь определяется тип Float с точностью (количеством десятичных цифр после запятой) D = 6.
Запись 16#0.FFFF_FF#E+32 - запись числа 3.40282E+38 в шестнадцатеричной форме. Расшифруем её:
1. Цифра 16 в данном случае означает систему исчисления (СИ) (шестнадцатеричная, может быть двоичная, восьмеричная, десятичная и т.д.).
2. Символы "#" обрамляют само число.
3. Символ "_" - разделитель между разрядами числа. Он допускается не только в шестнадцатеричной СИ, но и в любой другой. Например, записи 100000 и 100_000 аналогичны. Использовать или нет разделитель "_" - дело вкуса, но запись 100_000 воспринимается глазами лучше.
4. Символы E+32 означает "умножить на десять в тридцать второй степени"
Как и для целых типов в Аде существует возможность определять типы и подтипы для плавающих типов.
Для плавающих типов граница ошибки определяется заданием относительной погрешности в виде требуемого минимального числа значащих десятичных цифр (D).
Объявление плавающих типов выглядит примерно так:
type <Плавающий Тип> is digits 6; type <Плавающий Тип> is digits 6 range -100.54..100.54; type <Плавающий Тип> is New <Предопределенный Плавающий Тип>; subtype T is <Плавающий Тип> digits D [range <Плавающий Тип>(L) .. <Плавающий Тип>(R)]; |
Примеры определения типов и подтипов:
type COEFFICIENT is digits 10 range -1.0 .. 1.0; type REAL is digits 8; type MASS is digits 7 range 0.0 .. 1.0E35; subtype SHORTCOEFF is COEFFICIENT digits 5; -- подтип с меньшей точностью subtype PROBABILITY is REAL range 0.0 .. 1.0; -- подтип с меньшим диапазоном |
Рассмотрим пример задачи: дано положительное действительное число X. Выведите его дробную часть.
Формат входных данных:
Вводится положительное действительное число.
Формат выходных данных:
Выведите ответ на задачу.
Пример ввода:
17.9
Пример вывода:
0.9
with Ada.Float_Text_IO; use Ada.Float_Text_IO; --Подключаем пакеты для работы с типом Float procedure main is n : Float; begin Get(n); n := n - Float'Floor(n); -- Float'Floor() - округление "Вниз" (у положительного --числа это означает "отбросить дробную часть") Put(Item => n, Fore => 1, Aft => 2, Exp => 0); --Вывод вещественного числа, --можно так: Put(x, 1, 2, 0); end main; |
Разберём эту задачу. В пакете Ada.Float_Text_IO описан тип Float и команды для работы с этим типом. В первой строке программы мы подключаем этот пакет.
Как описано в комментарии, Float'Floor(n) - это округление числа "вниз", т.е. у положительного числа будет отброшена целая часть, а отрицательное число будет уменьшено до ближайшего целого (например, Float'Floor(10.6) = 10.0, а Float'Floor(-10.6) = -11).
Вывод Put(Item => n, Fore => 1, Aft => 2, Exp => 0) - это вывод вещественного числа. Вместо этой формы можно использовать более короткую запись: Put(x, 1, 2, 0).
Здесь:
- Item - это само выводимое число.
- Fore - количество цифр до точки (если указать их количество меньше, чем содержится в самом числе, то поле Fore будет автоматически расширено до нужной ширины)
- Aft - количество цифр, выводимых после точки.
- Exp - экспоненциальное представление числа (если 0, то вывод будет в обычной форме)
Фиксированные типы:
Представление чисел с фиксированной точкой имеет более ограниченный диапазон значений и указанную абсолютную погрешность, которая задается как delta этого типа. Значение должно быть вещественным числом больше 0.
Зачем нужен фиксированный тип? Во-первых, расчёты с фиксированным типом выполняются намного быстрее, чем с плавающим. Во-вторых, зачастую высокая точность расчётов не нужна. Например, в магазинах копейки считаются с точностью до двух знаков после точки и использовать более двух знаков смысла нет.
Общее описание фиксированного типа: type T is delta D range L .. R
Можно расписать определение типов и подтипов следующим образом:
type <Фиксированный тип> is new <Предопределенный Фиксированный Тип>; subtype T is <Фиксированный тип> delta D range <Фиксированный тип>(L) .. <Фиксированный тип>(R);
Например, в Аде предоставлен предопределенный вещественный тип с фиксированной точкой Duration, который используется для представления времени и обеспечивает точность измерения времени в 50 микросекунд:
type Duration is delta 0.000000001 range -((2 ** 63 - 1) * 0.000000001) .. +((2 ** 63 - 1) * 0.000000001); |
Примеры:
type VOLT is delta 0.125 range 0.0 .. 255.0; --погрешность - 0.125 subtype ROUGH_VOLTAGE is VOLT delta 1.0; --диапазон, как у VOLT, погрешность - 1.0 |
Вообще, типы - один из мощнейших инструментов языка Ада. Тема типов и их производных весьма обширна. Я буду вводить элементы по мере возникновения необходимости в них при решении задач. Для тех же, кто хочет досконально разобраться в системе типов языка Ада, советую обратится к книге Александра Гавва "Адское программирование".
Ещё хотелось бы отметить, что числа вещественного типа сравнивать друг с другом нужно очень осторожно, так как представление вещественных чисел в компьютере не точное. Например, число 0.1 в ПК может храниться как 0.09999999. Для сравнения вещественные числа можно, например, преобразовать в целые:
a := 0.1 b := 0.125 if Integer(a * 1000.0) < Integer(b * 1000.0) then... |
Тогда в сравнение можно заложить свою допустимую для данного примера погрешность.
Вообще сравнение вещественного типа - это проблема не Ады, а любого языка программирования, так как связана она не с реализацией компилятора, а с представлением чисел в компьютере.
Если изучение материала этой страницы не вызвало у Вас никаких затруднений, то Вы можете смело переходить к решению задач по этой теме.