Целые числа в языке Ада. Введение

Целые числа - это числа вида 1, 2, 10, 15, -10, -1, 0 и т.д. (т.е. у них нет дробной части).

При выполнении действий над целыми числами необходимо помнить, что приоритет операций в Аде тот же, что и в математике. Изменять последовательность вычислений можно с помощью скобок, как в математике.

При делении целых чисел друг на друга результатом будет целое число. Например, 5 / 2 равно 2. То есть, дробная часть отбрасывается. С помощью оператора rem можно получить остаток от деления. Например 5 rem 2 будет равно 1. (4 rem 2 равно 0).

Переменные

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

Можно рассматривать переменные как ящики разных форм (зависящих от того, что Вы собираетесь в них хранить), в которые можно положить предметы. Причём, каждый тип ящиков может хранить предметы только определённого вида (например, в треугольном ящике можно хранить только треугольные предметы, в квадратном — квадратные и т.д.). В ящик, предназначенный для хранения целых чисел, дробное число «не пройдёт по габаритам» и наоборот.

Размер целого типа ("ящика", в который можно положить число целого типа) зависит от архитектуры компьютера. Но в академических целях будем считать, что это числа из диапазона –215+1 .. +215-1 => -32768..32767.

Ада позволяет точно узнать размер типа данных для архитектуры, на которой она работает. Дело в том, что у типов в Аде есть так называемые атрибуты. С их помощью можно узнать минимальное и максимальное значение какого-либо типа. Например, запрос Integer'First - это первое (наибольшее по модулю отрицательное) целое, а Integer'Last - последнее (наибольшее) целое.

В имени переменной можно использовать буквы латинского алфавита, цифры и символ подчёркивания (первым символом должна быть буква). Ада не различает строчные и прописные буквы.

Объявим 2 целочисленные переменные X и Y (2 "ящика"):

X, Y : Integer;

Integer в переводе с английского означает «целое число». Таким образом, мы указали компилятору, что нужно взять 2 участка памяти (2 "ящика"), и этим участкам памяти присвоить имена X и Y. Каждый из этих участков памяти (каждая переменная) может хранить целое число из диапазона Integer'First..Integer'Last (для разных архитектур это будут разные значения, но, как мы договаривались (да и с целью кроссплатформенности), пусть это будут значения -32768..32767.

Также обращаю Ваше внимание, что в конце каждого законченного действия нужно ставить точку с запятой.

Для присваивания значения переменной в Аде используется набор символов ":=" (без кавычек). Общий вид:

X := 5;      --Присвоить переменной X значение 5
Y := 103; --эта запись эквивалентна Y := 7.

Текст, начинающийся с двух тире (−−) - это комментарий. Он игнорируется компилятором и используется как узелок на память о том, какое действие выполняется в строке.

Также присваивать значения переменным можно при их объявлении:

Z : Integer := 10;

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

Для решения задач нам понадобятся команды ввода и вывода данных: Get() и Put(). Для переменных целого типа их описание находится в пакете Ada.Integer_Text_IO.

Рассмотрим решение задачи: N белок нашли K орехов и решили разделить их поровну. Определите, сколько орехов достанется каждой белке. На вход дается два целых положительных числа N и K, каждое из которых не превышает 10000. Выведите одно целое число - ответ на задачу.

Пример ввода:
3 14
Пример вывода:
4

Решение:

with Ada.Integer_Text_IO; --Подключаем пакет для ввода/вывода целых чисел
use Ada.Integer_Text_IO;  --Сообщаем компилятору, что для работы с целыми числами реализацию
                          --команд (Get() и (Put()) нужно смотреть в этом пакете
 
procedure Main is         --Дальше следует блок объявления переменных
	N, K, Col : Integer; --Объявление трёх целочисленных переменных с именами N, K и Col
begin                     --конец блока объявления переменных и начало блока исполнения команд
	Get(N);             --Ввод первого числа
	Get(K);             --Ввод второго числа
	Col := K / N;       --Деление. Так как мы используем целые числа (а они не могут хранить
                        --дробную часть числа), то остаток от деления (дробная часть) будет отброшен
	Put(Col);           --Вывод результата
end main;

Подключение Ada.Integr_Text_IO даёт нам доступ к командам Get() и Put() для целых чисел. Процедура Get() позволяет считывать вводимые пользователем данные. Процедура Put() позволяет выводить числовые данные на экран. Однако в том виде, в каком мы использовали Put(), под выводимую переменную будет выделено гораздо больше места, чем требуется, и вывод будет выглядеть примерно так (без кавычек):

«            4»

Процедура Put() позволяет указать, сколько позиций минимум нужно выделить под переменную. Рассмотрим три варианта вывода.

with Ada.Integer_Text_IO;  use Ada.Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;                 --Для использования New_Line (перехода на новую строку)
 
procedure Main is
	N, K, Col : Integer;  
begin
	Get(N);
	Get(K);
	Col := K / N;
--ВАРИАНТ ПЕРВЫЙ
	Put(Item => Col, Width => 1); --Явное указание выводимого значения и ширины поля. Если ширина
                                  --поля будет недостаточна, то она расширится до нужных размеров.
                                  --Но в любом случае, если Width = 1, то выравнивание вывода
                                  --произойдёт по левому краю
	New_Line;                     --Переход на новую строку
--ВАРИАНТ ВТОРОЙ
	Put(Width => 1, Item => Col); --То же самое, что и в предыдущем выводе. Так как для вывода
                                  --используются именованные поля, то порядок следования полей не
                                  --имеет значения.
	New_Line;
--ВАРИАНТ ТРЕТИЙ
	Put(Col, 1);                  --Здесь для вывода используются неименованные поля, поэтому
                                  --порядок следования переменных имеет значение
 
end main;

Лично я предпочитаю Put(Item => Col, Width => 1). Это немного длиннее, зато повышается читабельность кода.

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

Показать

with Ada.Text_IO; use Ada.Text_IO;
 
procedure Main is
	package Int_IO is new Integer_IO (Integer); --Даем пакету Integer_IO для типа Integer ещё одно
                                                --имя (Int_IO)
	use Int_IO;                                 --и используем его для дальнейшей работы. Это
                                                --делает доступными Put() и Get() для типа Integer
	N, K, Col : Integer;
begin
	Get(N); Get(K);                             --Подпрограммы чтения переменных записаны в одной
                                                --строке 
	Col := K / N;
 
	Put(Item => Col, Width => 1);
end Main;

[свернуть]

Создание подтипов и производных типов

По условию задачи числа N и K не могут превышать 10000. Можно при вводе пользователем числа проводить проверку (в языке Си я бы так и сделал), а можно создать новый тип/подтип, который будет включать в себя только тот диапазон значений, который нам нужен. Ада позволяет создавать любые типы и подтипы с различными ограничениями. Рассмотрим дополнение данной задачи заданием ограничений N, K и Col.

Вариант 1 - создание подтипа:

Общая схема объявления подтипа:

subtype Название_Подтипа is Название_Родительского_Типа range Диапазон_значений;

С помощью ключевого слова subtype задаётся новый подтип.

С помощью ключевого слова range задаётся диапазон значений (это называется уточнением).

with Ada.Text_IO; use Ada.Text_IO;                  --Для текста
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;  --Для целых чисел
 
procedure Main is
	subtype Sub_Int is Integer range 1..10000; --Создаём подтип Sub_Int типа Integer с
                                               --ограничением от 1 до 10000. Т.е. переменные этого
                                               --типа не могут быть меньше 1 и больше 10000
	N, K, Col : Sub_Int;                       --Объявляем переменные созданного нами типа
begin
	Get(N); Get(K);                            --Так как "родителем" для Sub_Int является Integer, то
                                               --для Sub_Int доступны все команды, относящиеся к
                                               --типу Integer (в данном случае Get() и Put())
	Col := K / N;
 
	Put(Item => Col, Width => 1);
end main;

Вариант 2 - создание производного типа:

Общая схема объявления типа:

type Название_Типа is New Название_Родительского_Типа range Диапазон_значений;

С помощью ключевого слова type задаётся новый тип.

is New означает, что создаётся новый тип и далее будет следовать название родительского типа => создаваемый тип будет производным.

С помощью ключевого слова range задаётся уточнение типа (в данном случае range может и отсутствовать, тогда новый тип будет полностью совпадать с родительским типом).

Так как создаётся новый тип, то для того, чтобы считывать и выводить данные этого типа, необходимо либо самостоятельно создать команды ввода-вывода для него (например, с помощью дженерика Ada.Text_IO.Integer_IO. Что такое дженерик рассмотрим позже), либо использовать операцию приведения типа к родительскому (или ближайшему подходящему). Для приведения созданного типа к типу Integer используется команда Integer(Переменная_Созданного_Типа);

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
 
procedure Main is
	type New_Int is New Integer range 1..10000;       --Создаём новый тип New_Int с ограничением от
                                          --1 до 10000. Т.е. переменные этого типа не могут быть меньше 1 и
                                          --больше 10000
	N, K, Col : New_Int;
begin
	Get(Integer(N));                       --Так как для нового типа New_Int операция Get()
	Get(Integer(K));                       --не определена, следовательно, нужно "привести"
                                           --переменные типа New_Int к наиболее близкому (родительскому) типу,
                                           --для которого Get() определена. Integer(P) - операция
                                           --приведения переменной P к типу Integer
	Col := K / N;
 
	Put(Item => Integer(Col), Width => 1); --Тот же случай, что и с Get()
end main;

Если пользователь попробует ввести числа меньше 1 или больше 10000, будет возбуждено исключение, которое можно обработать (это отдельная тема и мы будем рассматривать её позднее). В любом случае некорректный ввод программа не пропустит.

Бывают ситуации, когда выгоднее создавать типы (например, чтобы пользователь не мог сложить 100 гвоздей и 20 яблок, можно создать разные типы для этих товаров, а так как по умолчанию разные типы в Ада смешивать нельзя, то такое сложение осуществить не получится), а бывает что и наоборот нужны подтипы (например, чтобы можно было просуммировать 10 кг яблок и 5 кг апельсинов).

Если создаются два типа с одинаковыми диапазонами значений:

type A_Type is New Integer range 1..1000;

type B_Type is New Integer range 1..1000;

переменные этих типов будут считаться переменными разных типов. Ада - строготипизированный язык и смешивать переменные разных типов типов не позволяет (без их предварительного приведения к какому-либо общему типу).

Механизм создания типов и подтипов в языке Ада - очень мощный инструмент, который позволяет избегать большого количества ошибок.

В следующем разделе мы попробуем решить несколько задач с использованием целых чисел. Для каждой задачи я предложу своё решение с комментариями. Мне кажется, что решение задач - самый короткий путь при изучении языка программирования.

Дополнительная информация:

Кроме подтипов и производных типов в Аде можно создавать анонимные типы:

type A_Type range 1..100; −−объявление анонимного типа с диапазоном значений от 1 до 100

A : A_Type; −−объявление переменной созданного ранее типа

Можно также непосредственно объявить переменную и задать ей диапазон значений:

B : range 0..1000; −−B - целая переменная анонимного типа с диапазоном значений от 0 до 1000

В следующем разделе рассмотрены некоторые задачи и примеры их решения на языке программирования Ада

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *