Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции ЯП (Кузьмин) ч.2_new (Паскаль).docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
4 Мб
Скачать
☆

1 Группа функций:

Следующие стандартные процедуры и функции могут применяться и использоваться с аргументами целых типов (x, y – целое число) и возвращают целое или порядкового типа значение:

x DIV y – целочисленное деление

x MOD y – остаток от целочисленного деления

Abs(x) – функция, возвращает значение модуля числа (абсолютного значения) в точку вызова

Chr(x) – функция, возвращает символ с кодом, равным значению аргумента

Dec(x) – процедура, выполняет уменьшение аргумента на единицу или на заданное значение

Inc(x) - процедура, увеличивает аргумент на единицу или на заданное вторым аргументом значение

Lo(x) – функция, возвращает в точку вызова значение младшего байта Low(x)

Hi(x) - функция, возвращает в точку вызова значение старшего байта High(x)

Swap(x) - функция, выполняет следующее действие над двухбайтовыми аргументами: меняет местами старший и младший байты

Замечание: для Lo(x), Hi(x) и Swap(x) аргумент может быть или типа Word или Integer

Odd(x) -функция, возвращает в точку вызова логическое значение “истина”, если значение аргумента нечетно, или “ложь”, если значение аргумента четно

Random(x) – функция, возвращает в точку вызова случайное число из диапазона от 0 до значения аргумента (само значение аргумента не включается в этот диапазон).

Sqr(x) функция, возведение аргумента в квадрат

(для сравнения: Sqrt (x) функция для извлечение квадратного корня из вещественного аргумента, возвращает вещественный результат )

2 Группа функций:

Следующие функции всегда возвращают вещественное значение при целочисленных аргументах:

Sin (x), Cos (x), Arctan (x), Ln (x), Exp(x)

3 Группа функций:

Следующие функции при вещественном аргументе всегда возвращают целые значения:

Round(x) – функция, округляет вещественное значение до ближайшего большего целого и возвращает его в точку вызова (Round(1.2)=1, Round(1.5)=2, Round(1.9)=2).

Trunc(x) – функция, отсекает дробную часть и возвращает результат в точку вызова. Есть функции, делающие обратное:

Frac(x) – функция, отбрасывает целую часть и возвращает в точку вызова дробную

Int(x) - функция, возвращает для вещественного аргумента целое число, являющееся округлением аргумента до ближайшего меньшего (в сторону 0) целого.

Например, Int(1.45) = 1

Int(1.9) = 1

Int(-1.9) = -2

trunc(1.45) = 1

trunc(1.9) = 1

trunc(-1.9) = -1

Замечание по поводу функций и процедур: процедура и функция отличаются формой вызова.

Пример:

Var

x,

y: integer;

begin

x:-10;

Dec(x); //Вызов процедуры Dec с фактическим параметром х

randomize; //Процедура без параметров. Вызывать надо перед random, чтобы инициализировать

// датчик случайных чисел

y:=random(x); //Вызов функции Random с фактическим параметром х

Операция в языках программирования – это элементарное действие, вырабатывающее некоторое значение (результат операции). По числу операндов операции делятся на одноместные и двухместные. По типу операндов и результата операции делятся: 1) арифметические (операнды – числа, результат – число); 2) логические (операнды – логические, результат – логический); 3) отношения (операнды – произвольные, результат – логический).

Над данными целых типов, как и над данными любых других типов, можно производить операции отношения. Эти операции записываются следующим образом:

x = y

x > y

x < y

x <> y

x >= y

x <= y

Арифметические операции, которые могут применяться с использованием данных целых типов:

+,

-,

*,

/.

div - операция целочисленного деления (без остатка)

mod - остаток от целочисленного деления

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

  • если оба операнда у первых 3 операций - целого типа, то будет получен результат целого типа.

  • если хотя бы один из операндов у первых 3 операций - вещественного типа, то результат получится вещественного типа.

  • операция деления всегда возвращает вещественный результат (несмотря на тип операндов).

К данным целого типа применимы также поразрядные операции. Они выполняются над каждой парой одноименных разрядов операндов. Рассмотрим правила выполнения поразрядных операций над одним из разрядов (например, с номером i):

*

x1

x2

x3

…

xi-1

xi

…

xn-1

xn

y1

y2

y3

…

yi-1

yi

…

yn-1

yn

z1

z2

z3

…

zi-1

zi

…

zn-1

zn

Обобщенное обозначение поразрядной операции:

zi = xi * yi

Var

x:byte; x = 2

y:byte; 00000010

begin

x := 2; 11111101

y := not x; y = 253

end.

not x = 253

Поразрядное “НЕ” (одноместная операция)

Xi

not Xi

0

1

1

0

Поразрядное “И” или поразрядное умножение (двухместная операция)

Xi

Yi

Xi and Yi

0

0

0

0

1

0

1

0

0

1

1

1

Поразрядное “ИЛИ” или поразрядное сложение (двухместная операция)

Xi

Yi

Xi or Yi

0

0

0

0

1

1

1

0

1

1

1

1

Поразрядное “ИСКЛЮЧАЮЩЕЕ ИЛИ”. Эта операция устанавливает результат, равным единице, при несовпадении соответствующих разрядов (двухместная операция):

Xi

Yi

Xi xor Yi

0

0

0

0

1

1

1

0

1

1

1

0

Поразрядный сдвиг вправо и влево достигается применением операций (двухместных):

X Shl Y - значение X сдвигается влево на Y разрядов

X shr Y - значение X сдвигается вправо на Y разрядов.

Можно считать, что при выполнении сдвигов мысленная граница разрядной сетки для типа числа (правая или левая) сдвигается на соответствующее число разрядов (вправо или влево):

При сдвиге вправо мысленная правая граница (где заканчивается целая часть числа) перемещается влево;

При сдвиге влево мысленная левая граница (за самым старшим разрядом) перемещается вправо.

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

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

При сдвиге вправо отрицательных чисел типов shortint, integer и longint (они могут иметь отрицательные значения) в освободившиеся слева разряды записываются копии знакового разряда. При этом сам знаковый разряд циклически при каждом шаге сдвига восстанавливается на своем старом месте.

При сдвиге этих же чисел влево знаковый разряд замещается тем значением, которое придет справа. Но так происходит лишь если выключена опция компилятора Range Checking (Options – Compiler – Generated code – Range Checking). Если же она включена, то при попытке изменить знаковый разряд получим сообщение о выходе за границы диапазона (Range check error).

Эти поразрядные логические операции используются для выполнения следующих действий:

1) выделение нужного фрагмента двоичного кода

2) очистка (установка в ноль) нужного фрагмента двоичного кода

3) проверка (равен 0 или 1) разрядов нужного фрагмента двоичного кода

4) инвертирование нужного фрагмента двоичного кода (весь код можно проинвертировать с помощью операции not)

5) занесение единицы в нужные разряды двоичного кода без имени (литерал)

Во всех далее рассматриваемых случаях все действия выполняются с использованием поразрядных операций и так называемой маски (вспомогательный двоичный код – константа, которой требуется при выполнении 2-местной операции для получения нужного результата и это значение для каждого конкретного случая (из пяти вышеуказанных) устанавливается по своему).

ПРИМЕР 1. Рассмотрим выделение из всего двоичного кода нужных разрядов.

Пусть имеется следующее объявление двух переменных:

Var

c : word; {Результат выделения}

w: word; {Исходное число}

В этом случае выделение из 2 байтов переменной w семи младших разрядов будет выглядеть следующим образом:

c := w and $ 7F 7 разрядов

маска = 0000 0000 0111 1111

----- ----- ------ -----

0 0 7 F

Маска формируется по следующему правилу: нужно поставить в единицу те разряды, которые вы хотите выделить.

ПРИМЕР 2. Установка в ноль (очистка) 7 младших разрядов.

Var

c, w: word;

Begin

c := w and $ FF80

здесь маска имеет вид:

1111 1111 1000 0000

F F 8 0

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

ПРИМЕР 3. Проверка заданных разрядов. Может выполняться с помощью условного оператора языка Паскаль, маски и поразрядной операции and. В условном операторе выполняется проверка на совпадение результата операции and с маской.

Var

w: word; {анализируемое число}

Begin

if (w and маска) = маска

then …..{если совпало}

else ……{если не совпало}

Например: if (i and 3) = 3 ------------------------ проверка младших двух разрядов

Маска в этом случае формируется следующим образом: в маске все разделы устанавливаются в ноль, кроме тех, которые вы хотите проверить (проверка: есть ли единицы в этих разрядах).

ПРИМЕР 4. Инвертирование избранных разрядов числа.

Var

c, w: word;

Begin

c := w XOR $7;

В данном случае тоже используется маска, в которой в единицу устанавливаются только те разряды, которые вы хотите проинвертировать (в примере - три младших разряда).

Примечания:

  1. если эта операция повторяется два раза, то значение исходного числа восстановится;

  2. имеется поразрядная операция NOT, но она инвертирует все разряды, а нам необходимо инвертировать только некоторые

ПРИМЕР 5. Установка (занесение 1) в три младших разряда (остальные остаются без изменения):

Var

c, w: word;

Begin

c := c OR $7;

Здесь в маске устанавливают в единицу те разряды, в которые надо занести единицу.

ПРИМЕР 6 (Более сложный). Пусть надо выполнить комбинированное действие – из двух переменных (одна представляет собой младшее слово, вторая – старшее слово многословного числа) типа Word (2 байта) собрать одну типа Longint (4байта).

high_word low_word

Longint

Var

high_word: word;

low_word: word;

long_word: longint;

begin

high_word:=$7F00; Приведение к типу Longint

low_word:= $00FE;

long_word:= (longint(high_word) shl 16) + longint(low_word);

end.

ЗАМЕЧАНИЕ: Во всех рассмотренных пяти примерах есть одна особенность: вид маски зависит от разрядности числа. Рассмотрим, например, маску, которая используется в операции очистки 7 младших разрядов числа типа Word. Если мы захотим с помощью той же самой маски очистить младшие 7 разрядов, но уже в переменной longint, то очистятся 7 младших разрядов + 16 старших разрядов.

Var

c: longint; {Раньше был тип Word}

c := c AND $FF80;

Так произойдет потому, что применительно к типу longint маска фактически будет иметь запись 0000FF80. То есть, для типа longint маска должна была бы иметь вид FFFFFF80. Вывод из этого : для достижения универсальности надо стремиться к тому, чтобы запись маски не зависела от разрядности числа, к которому она применяется.

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

Not ($7F)

0111 1111

Если в общем случае нужно получить маску из n единиц, например, начиная с k-го разряда вправо n единиц (k считается справа налево, начиная с 1), то значение этой маски можно получить следующим образом:

к=8 к=1

m := (not( (not 0) shl n)) shl (k - n) 1 1 1 1

будут получены все единицы n=4 разрядов

справа будут получены n нулей к=6

из n нулей будет получено n единиц

единицы перегоняются на заданную k позицию

Если надо получить маску из n единиц, начиная с k-го разряда (но k считается теперь слева направо начиная с 1 до sizoeof(m)*8), то значение этой маски можно получить следующим образом:

m := (not( (not 0) shl n)) shl (sizeof(m)*8 – k) ;

где sizeof(m) – размер типа в байтах