Лекция 4 Работа с порядковыми типами

4.1.1 Общие свойства. К порядковым типам относятся типы данных, значения которых исчерпываются конечным упорядоченным в известном смысле множеством. Сюда входят тип диапазон, а также целые, логические, символьные и перечисляемые типы. Константы и переменные порядковых типов характеризуются следующими свойствами: каждый из них имеет конечное число значений, значения для каждого типа упорядочены, каждому значению соответствует порядковый номер, являющийся целым числом (нумерация элементов порядкового типа начинается с нуля).

Для данных порядкового типа вводится понятия предыдущего и последующего значений по отношению к данному. Например, порядковый номер символа ‘Ж’ для символьного типа Char равен 134. Предыдущим для него символом является ‘Е’ с порядковым номером 133.

4.1.2 Целые типы. Целые типы предназначены для описания целых чисел. Они подразделяются на пять видов: Byte, ShortInt, Integer, Word, LongInt. Константа или переменная типа Byte может принимать значение от 0 до 255 включительно, которое во внутреннем представлении занимает один байт памяти. Характеристики других типов целых чисел приведены в табл. 3.2.

Таблица 3.2 - Характеристика целых типов чисел

Имя типа

Характеристика

числа данного

типа

Диапазон изменения чисел

Занимаемая

память в

байтах

 

Byte

Целое короткое без знака

0...255

1

 

ShortInt

Целое короткое

со знаком

-128...127

1

 

Integer

Целое со знаком

-32768...32767

2

 

Word

Целое без знака

0...65535

2

 

LongInt

Целое длинное

со знаком

-2

4

Синтаксическая диаграмма целого числа имеет вид:

НЕ нашли? Не то? Что вы ищете?

Синтаксическая диаграмма знака представлена в пункте 4.2.2.

Пример описания констант и переменных целого типа в разделе объявлений программы:

Const

I=7; A=1500;

Var

X:Integer; Y:LongInt;

Над целыми числами можно производить операции сложения (+), вычитания (-), умножения (*), целочисленного деления (div) и операцию выделения остатка от деления mod. Полученный результат остаётся в области целых чисел. Примеры:

3*4 равно 12; 7-2 равно 5; 7 mod 4 равно 3.

Целочисленное деление сохраняет только целую часть. Пример: 9 div 5 равно 1.

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

Если в одном выражении производится несколько операций, то они выполняются слева направо с учётом приоритета - сначала выполняются умножение или деление, затем сложение или вычитание. Указанный приоритет может быть изменён с использованием круглых скобок в соответствие с правилами, действующими в арифметике. Пример:

- результат вычисления выражения 9+5 * 3 равен 24;

- результат вычисления выражения (9+5) * 3 равен 42.

В процессе арифметических действий возможен выход за пределы допустимых значений, что приведёт к переполнению и появлению ошибки. Пример. Пусть в разделе описания программы имеется строка с объявлением переменной N:

Var N:Integer;

Если в исполняемой части программы производится перемножение достаточно большого числа N на число N, когда результат выходит за допустимый интервал, предусмотренный типом данных Integer, то это приведёт к ошибке. Так, при N=30000 выполнение умножения N*N даст число -5888!

Операнды, используемые в рамках одной операции, могут иметь разный тип. Спрашивается, какому типу будет принадлежать результат? Для ответа на поставленный вопрос введём понятие о старшинстве типов. Ниже приведены типы в порядке убывания старшинства:

- тип LongInt,

- типы Word, Integer,

- типы Byte, ShortInt.

Существует правило:

- если операнд содержит два целых числа с типами Word и Integer, то результат операции принадлежит типу LongInt;

- результаты операций в пределах одного типа принадлежат этому типу;

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

Var

X_Int:Integer; X_Word, Y:Word;

Begin

X_ Int:=30000; X_Word:=60000;

Y:=X_Int+X_Word; WriteLn(Y)

End.

должна выводить на экран число 90000. Но вследствие нарушения правила старшинства на экране высветится 24464! Ошибка.

4.1.3 Булевские типы. Седьмая версия Турбо Паскаля позволяет работать с четырьмя типами логических данных: тип Boolean, используемый во всех версиях Паскаля, включая шестую, и новые булевские типы ByteBool, WordBool, LongBool, введённые в седьмую версию. Константы и переменные булевских типов могут принимать одно из двух значений False (ложь) и True (истина). Характеристика типов представлена табл. 4.1.

Таблица 4.1 - Характеристика булевских типов

Имя типа

Выделяемая

память, байты

Значению False со-

ответствует

Значению True со-

ответствует

Boolean

1

Число 0

Любое

целое число

отличное

от нуля

ByteBool

1

Число 0

WordBool

2

Число 0 в обоих байтах

LongBool

4

Число 0 в обоих байтах

В ранних версиях Паскаля переменная булевского типа занимала 1 байт, значению типа False соответствовало число 0, а значению True – число 1. В седьмой версии, как видно из табл. 4.1, ситуация изменилась. Данные булевского типа занимают во внутреннем представлении от 1 до 4 байтов, а значению True отвечает любое целое число, отличное от 0. Это не влияет на использование новых типов в константах, переменных и логических выражениях. Так, программа с переменными различных булевских типов

Var

B1:Boolean;B2:ByteBool;B3:WordBool;B4:LongBool;

Begin

B1:=True;B2:=True;B3:=True;B4:=True;

WriteLn(B1,' ',B2,' ',B3,' ',B4);

B1:=False;B2:=False;B3:=False;B4:=False;

WriteLn(B1,' ',B2,' ',B3,' ',B4)

End.

выдаст на экран одинаковое значение False для всех переменных. Различие сказывается при работе со встроенными функциями, в чём мы убедимся позднее в п. 4.2.4.

4.1.4 Символьный тип. Значением типа Сhar может быть любой символ, предусмотренный кодировкой ASCII. Им может быть цифра, буквы, специальные символы и управляющие символы с кодами от 0 до 31. Управляющие коды обеспечивают специфические операции языка Турбо Паскаль. Например, код 7 соответствует звонку. При задании значений типа Char последние выделяются апострофами. Пример задания символьных типов и работы с ними:

Const

Name='$'; {Задание константы Name типа Char, равной $}

Var

C1,C2:Char; {Объявление переменных C1,C2 типа Char}

Begin

C1:=Name; {Присвоение переменной С1 типа Char значе-

ния константы Name типа Char}

C2:='Q'; { Присвоение переменной С2 типа Char значения Q }

WriteLn(Name,' ', C1,' ', C2); {Вывод на экран констант и переменных}

End.

Упорядочение значений типа Char определяется в соответствие с кодом ASCII данного символа.

4.1.5 Перечисляемый тип. Перечисляемый тип задаётся перечислением всех возможных значений, задаваемых правильными идентификаторами. Пример задания перечисляемого типа:

Type

Dweeks = (Monday, Thirsday, Sonday)

Переменная типа Dweeks может принимать одно из трёх значений: Monday, Thirsday или Sonday. Каждый элемент перечисляемого типа является уникальным идентификатором и рассматривается как константа. Сами идентификаторы нельзя путать со строковыми константами – они не берутся в кавычки. Один и тот же идентификатор не может использоваться при определении типа в двух местах. Элементами перечисляемого типа не могут быть константы предопределённого типа, например константы символьного(‘q’, ‘w’, ’e’), числового (1, 2, 3) или строкового (‘asd’, ‘tuber’) типов. Ниже приведён пример работы с данными перечисляемого типа Dweeks:

Var

Day:Dweeks; {Задание переменной Day перечисляемого типа }

Begin

Day:=Monday; {Переменной перечисляемого типа присваивается один

из элементов типа Tweeks}

………………………………………………………………………………

Упорядочение элементов данного типа проводится в соответствие с их положением при описании. Первый элемент списка имеет порядковый номер 0, второй 1 и т. д. К значениям перечисляемого типа не применимы арифметические операции и стандартные процедуры ввода-вывода Read, Write, ReadLn, WriteLn. Если в текст приведённого фрагмента включить строку для вывода значения переменной Day

WriteLn(Day);

то выполнение программы будет прервано, и на экране высветится сообщение об ошибке

Error 64: Cannot Read or Write variables of this type.

4.1.6 Тип диапазон. Тип диапазон представляет собой интервал значений любого порядкового типа, называемого базовым типом. Поэтому его можно рассматривать как подмножество из элементов порядкового типа. Тип диапазон для целых чисел описывается путём задания наименьшего и наибольшего значений. Например,

Var

X:2..8;

В случае других базовых типов первым указывается элемент с наименьшим порядковым номером, второй – с наибольшим порядковым номером. Пример.

Var

S:’a’..’e’.

Переменные этого типа сохраняют все свойства базового типа данных.

4.2 Стандартные функции для работы с данными простых типов

4.2.1 Арифметические функции. Арифметические выражения могут содержать не только элементарные арифметические операции с числами, но и более сложные математические операции, для выполнения которых используются так называемые стандартные или встроенные функции. Их функционирование поддерживается стандартным модулем ИСР System, который обеспечивает выполнение ряда операций, связанных с возведением числа в квадрат, определением синуса или косинуса от данного аргумента и т. д. Например, стандартная функция Sqr(Х) от аргумента, являющегося вещественным числом, возвращает квадрат аргумента.

Фрагмент программы

X:=16;

Y:=Sqrt(X):Z:=Sqr(X);

Writeln(Y,’ ‘,Z);

содержит две стандартные функции. Одна из них Sqrt(X) вычисляет квадратный корень из числа, хранящегося в ячейке памяти Х и равного 16, и помещает результат в ячейку Y, а другая - Sqr(X) возводит 16 в квадрат и помещает результат в ячейку Z. После выполнения фрагмента на экране появятся два числа: 4 и 256.

Полный список стандартных арифметических функций приведён в табл. 4.3. Их имена включены в список стандартных слов. Обратим внимание, что все стандартные функции, применённые к вещественным числам, возвращают значения, относящиеся к вещественным числам. Использование функций Sqr и Abs к аргументам для целых чисел возвращает целые числа.

Таблица 4.3 Стандартные арифметические функции

Вид алгебраической функции.

Встроенная функция.

Генерирование вещественного случайного числа, равномерно распределённого в интервале [0,1).

Random

Возвращение дробной части вещественного числа Х.

Frac(Х)

Возвращение целой части вещественного числа Х в виде вещественного числа.

Int(X)

½X½

Abs(X)

Arctg(X)

ArcTan(X) , аргумент в радианах

Cos(X) , аргумент в радианах

Cos(X)

еX

Exp(X)

Ln(X)

Ln(X)

Число p

Pi

Sin(X) , аргумент в радианах

Sin(X)

X2

Sqr(X)

Ö X

Sqrt(X)

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

при a=2,4, b=-3,1 x=4,8.

Фрагмент программы для расчёта этого арифметического выражения

A:=2.4;B:=-3.1;X:=4.8;

Y:=4.2*A+B*Sin(1+X*Ln(X));

Y:=Y/(Sqr(A)+Sqr(B));

WriteLn('Y=',Y:3:3);

выведет на экран: Y=0.498.

Функция Random возвращает случайное число, равномерно распределённое в интервале [0,10). Она позволяет построить генератор чисел из любого интервала [a, b). Легко показать, что таким генератором будет функция

a+(b-a)*Random

Рассмотрим работу фрагмента программы

X:=Random;

Writeln(X); {2}

A:=10;B:=30; {3}

Y:=A+(B-A)*Random; {4}

Z:=Sin(Y);

Вторая строка фрагмента обеспечивает вывод на экран случайного числа из интервала [0,1). С одинаковой степенью вероятности им может быть 0.00012, 0.98437 или, скажем, 0.12345. Пусть, например, случайное число оказалось равным 0.50000. В четвёртой строке программы генерируется случайное число из интервала [10,30). Пусть, например, оно равно 25.0000. Это число помещается в ячейку памяти Y, после чего определяется его синус, который помещается в ячейку памяти Z.

Функция Random построена таким образом, что при повторном запуске той же программы значения Х и Y принимают прежние значения. Если Вас такая ситуация не устраивает, пользуйтесь процедурой Randomize. При повторном запуске программы она изменяет стартовую позицию генератора и в случае использования функции Random позволяет получить новую серию случайных чисел.

4.2.2 Функции преобразования типов. Пусть имеются переменные Х1 и Х2, относящиеся, соответственно, к типам Т1 и Т2. В общем случае использование операции присвоения Х1:=Х2 на языке Турбо Паскаль запрещается. Это ограничение связано с тем обстоятельством, что данные разного типа на языке машинных команд представляются различным способом. Однако нет правил без исключения. Операция присвоения для различных типов разрешается в следующих случаях:

- Т1 и Т2 являются тождественными типами;

- тип Т1 объявлен как поддиапазон типа Т2;

- тип Т2 объявлен как поддиапазон типа Т1, но значение Х1 включено в область допустимых значений Т2;

- тип Т1 является вещественным, а тип Т2 целым.

Примеры.

1).Программа

Type

T1=Char;T2=Char;

Var

Char1:T1; Char2:T2;

Begin

Char2:=#100; CHAR1:=CHAR2; WriteLn(CHAR1,' ',CHAR2)

End.

содержит две переменные одного и того же типа. Поскольку код 100 определяет символ d, она выводит его на экран дважды.

2).Пусть тип Т2 в соответствие с объявлением

Type

T1=100..255;T2=101..103;

Var

X1:T1; X2:T2;

является поддиапазоном типа Т1. В соответствие со вторым правилом совместимости типов использование операции присвоения правомочно и программа:

Begin

X2:=102;X1:=X2;

WriteLn(X1,' ',X2)

End.

дважды выведет на экран число 102.

Попытка присвоить значение переменной более общего типа переменной типа, являющегося его поддиапазоном, может привести к ошибке, не контролируемой компилятором. Так, для переменных Х1, Х2 типа Т1, Т2, заданных в только что рассмотренном примере, программа

Begin

X1:=250;X2:=X1;

WriteLn(X1,' ',X2)

End.

выдаст на экран два числа 250 и –6. Абсурдный результат! Ранее, в пункте 4.2 рассмотрены казусные результаты в случае использования переменных различных целых типов в арифметических выражениях. Подобные ошибки не контролируются компилятором, поэтому работа с данными разных типов требует особого внимания.

ИСР Турбо Паскаль предусматривает возможность преобразования типа данных. Для этого существуют стандартные функции Round(X), Trunc(X), Ord(X), Chr(X). Функция Round(X) преобразуют вещественное число Х в целое путём его округления. Функция Trunc(X) осуществляет преобразование вещественного числа в целое путём его урезания дробной части. Примеры:

функция Round(1.8) возвращает 2;

функция Trunc(1.8) возвращает 1;

функция Round(-1.8) возвращает –2;

функция Trunc(-1.8) возвращает -1.

Функция Ord(X) преобразует элемент типа Char в целое число Byte, являющееся его кодом в системе ASCII, или возвращает порядковый номер элемента порядкового типа. Функция Chr(X) осуществляет преобразование символьной переменной в десятичный код ASCII. Пример. Программа

Var

Ch:Char;Name:(Ira, Ivan, Peter);

Begin

Ch:=’S’; WriteLn(Ord(Ch));

Name:=Ira; WriteLn(Ord(Name))

End.

высветит на экране число 83, являющееся кодом символа S, и порядковый номер значения переменной Name, равный 0.

4.2.3 Функции для работы с данными порядкового типа. Стандартные функции для работы с данными порядкового типа сведены в табл. 4.4. Действие функций Sqr(X), Abs(X), Abs(X), Ord(X) описано раньше. Функции Pred(X) и Succ(X) возвращают значения элементов, расположенных до и после элемента Х. Функция Odd(N) определяет нечётность целого числа. В случае нечётного N она возвращает значение True, в случае чётного - False. Функция Random(N) генерирует случайное целое число, равномерно распределённое в интервале от 0 до N-1.

Таблица 4.4 - Стандартные функции и процедуры для работы с данными порядкового типа

Стандартная функция

Выполняемое действие

Random

Генерирование целого случайного числа, равномерно распределённого в интервале от 0 до N-1.

Sqr(X)

Возведение числа Х в квадрат.

Abs(X)

Определение модуля числа Х.

Chr(N)

Возвращение символа в соответствие с кодировкой ASII.

Succ(X)

Возвращение значения, стоящего после элемента Х порядкового типа.

Pred(X)

Возвращение значения, стоящего перед элементом Х порядкового типа.

Ord(X)

Возвращение порядкового номера элемента Х порядкового типа.

Odd(N)

Проверка целого числа на его нечётность. Возвращает True для нечётного числа и False для чётного.

Пример программы c преобразованием переменных перечисляемого типа представлен ниже.

Type

Season=(Winter, Spring, Summer, Autumn);

Var

X, Y:Season;

Begin

X:= Summer;

WriteLn(Ord(X)); {На дисплей выводится порядковый номер 2}

WriteLn(Pred(X)); { Ошибка! Процедура WriteLn не может выводить

значения порядкового типа }

Y:=Pred(X);

WriteLn(Ord(Pred(X)):5,Ord(Succ(X))); {Выводятся порядковые номера

элементов, стоящих до и после значения Summer, т. е. числа 1 и 3}

WriteLn(Ord(Y)){Выводится порядковый номер элемента Spring,

т. е. число 1 }

Y:= Winter;

WriteLn(Ord(Pred(Y))){Выводится число –1, которому не отвечает ни

одному из значений элементов типа Season}

End.

В дополнение к функциям 4.4 отметим функцию UpСase(‘X’), которая преобразует строчный буквенный символ латиницы в прописной символ. Если в качестве Х взять другие символы (кириллица, цифры и т. д.), то функция вернёт его без преобразования. Пример. Программа

Begin

WriteLn(Upcase(‘s’), ‘ ‘,Upcase(‘7’) , ‘ ‘,Upcase(‘W’) , ‘ ‘,Upcase(‘ж’) )

End.

выводит на экран символы

S 3 W ж

4.2.4 Преобразование данных булевского типа. Введение новых булевских типов ориентировано на использование операционной системы Windows, в которой значению False отвечает число 0, а значению True – любое целое число, отличное от 0. Посмотрим, как это нововведение скажется при использовании функций преобразования типов Pred и Succ. Составим простую программу под именем Primer1

Program Primer1;

Var

Bool:Boolean;

Begin

Bool:=False;

WriteLn('Pred(Bool)=',Pred(Bool),' Bool=',Bool,' Succ(Bool)=',Succ(Bool));

Write('Ord(Pred(Bool))=',Ord(Pred(Bool)),' Ord(Bool)=',Ord(Bool));

WriteLn(' Ord(Succ(Bool))=',Ord(Succ(Bool)))

End.

выполняющую преобразование переменной Bool со значением False типа Boolean с использованием функций Ord, Pred и Succ. На экран выводится сообщение:

Pred(Bool)=TRUE Bool=FALSE Succ(Bool)=TRUE

Ord(Pred(Bool))=-1 Ord(Bool)=0 Ord(Succ(Bool))=1

из которого видно, что значению True могут соответствовать различные числа, равные –1 и +1. Это обстоятельство является особенностью булевских переменных.

Выход значения переменной за допустимый данным типом диапазон значений контролируется директивами компилятора {$R+} {$R-}. Объявление этих директив в приведённой программе никак не сказывается на её выполнении.

Запустим программу Primer1 со значением переменной TRUE. На экране появится сообщение:

Pred(Bool)=FALSE Bool=TRUE Succ(Bool)=TRUE

Ord(Pred(Bool))=0 Ord(Bool)=1 Ord(Succ(Bool))=2

В данном случае вместо ожидаемого результата Succ(Bool)=FALSE на экране высветилось TRUE, а порядковый номер значения Succ(Bool), равного True, оказался равным не 1, как в первой программе, а 2! Ничего не поделаешь – таковы правила, с которыми придётся считаться.

Составим ещё одну программу с именем Primer2, в которой тип логической переменной Bool заменим на один из типов ByteBool, WordBool или LongBool. Результат останется прежним и будет зависеть только от значения переменной False или True. Спрашивается, для чего вводить четыре логических типа, если между ними нет разницы? Оказывается есть. Она проявляется в одном случае, когда функция преобразования типа Ord применяется к булевским переменным, значения которых получены путём воздействия функций Pred и Succ на другие логические переменные. Обратимся к тексту программы Primer3:

Program Primer3;

Var

PBool, Bool, SBool:Boolean;

PBoolB, BoolB, SBoolB:ByteBool;

Begin

Bool:=False;BoolB:=False;

PBool:=Pred(Bool);SBool:=Succ(Bool);

WriteLn('Pred(Bool)=',PBool,' Bool=',Bool,' Succ(Bool)=',SBool);

Write('Ord(Pred(Bool))=',Ord(PBool),' Ord(Bool)=',Ord(Bool));

WriteLn(' Ord(Succ(Bool))=',Ord(SBool));

PBoolB:=Pred(BoolB);SBoolB:=Succ(BoolB);

WriteLn('Pred(BoolB)=',PBoolB,' BoolB=',BoolB,' Succ(BoolB)=',SBoolB);

Write('Ord(Pred(BoolB))=',Ord(PBoolB),' Ord(BoolB)=',Ord(BoolB));

WriteLn(' Ord(Succ(BoolB))=',Ord(SBoolB))

End.

В этой программе выполняются операции с двумя группами переменных типа Boolean и ByteBool. Результатом её выполнения будет:

Pred(Bool)=TRUE Bool=FALSE Succ(Bool)=TRUE

Ord(Pred(Bool))=-1 Ord(Bool)=0 Ord(Succ(Bool))=1

Pred(BoolB)=TRUE BoolB=FALSE Succ(BoolB)=TRUE

Ord(Pred(BoolB))=1 Ord(BoolB)=0 Ord(Succ(BoolB))=1

Для переменной типа Boolean на экране высвечивается та же информация, что и в программе Primer1. Но в случае переменной типа ByteBool она изменилась - функция Ord(Pred(BoolB)) вместо числа –1 возвратила число 1.

Заменим значения переменных Bool и BoolB в программе с именем Primer3 на значение True. После её запуска на экране высветится:

Pred(Bool)=FALSE Bool=TRUE Succ(Bool)=TRUE

Ord(Pred(Bool))=0 Ord(Bool)=1 Ord(Succ(Bool))=2

Pred(BoolB)=FALSE BoolB=TRUE Succ(BoolB)=TRUE

Ord(Pred(BoolB))=0 Ord(BoolB)=1 Ord(Succ(BoolB))=1

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