Булевский (логический) тип
Логическое значение - это одно из двух значений истинности, которые обозначаются предопределенными именами false и true. Переменные этого типа занимают 1 байт, однако в Турбо Паскале версии 7.0 определены 3 логических типа: Bytebool (1 байт), Wordbool (2 байта), Longbool (4 байта) Значению “истина” в памяти при хранении значения соответствует 1, значению “ложь” – 0 (т.е. 0 и 1 – это внутреннее представление значений истина и ложь). При этом false < true.
Операции отношения всегда дают логический результат. Например, отношение
x + 1 < y
при x = 0, y = 0 дает false; при x = 0, y = 10 - значение true.
Var b: boolean; - обозначение булевского типа.
Три стандартные функции для порядковых типов применимы и к этому типу:
Ord (true) = 1, Ord (false) = 0
Pred (true) = false
Succ (false) = true
С переменными булевского типа можно использовать следующие логические операции:
· not
X not X
false true
true false
· and, or, xor
X | Y | X and Y | X or Y | X xor Y |
false | False | false | False | false |
false | True | false | True | true |
true | True | true | True | false |
true | False | false | True | true |
Эти операции похоже на те, которые используются применительно к целым типам. Существуют отличия (особенности):
1. логические операции применимы только к логическим типам
2. логическими операциями возвращается результат логического типа.
3. значение операнда принимает участие в операции целиком (полностью, а не поразрядно, как для целых чисел),
Используются логические переменные в следующих конструкциях: операция отношения
1)
FALSE < TRUE истина FALSE = TRUE ложь |
2) repeat тело_цикла until (логическое_выражение);
3) b:= логическое_выражение
4) if (логическое_выражение)
then...действие_если_истина..
else действие_если_ложь.;
Пример более сложного логического выражения:
((x + 1 < y) and not (x > 5)) or ((y > 0) and true)
Вычислим значение этого выражения при x = 5, y = 5:
((6 < 1) and not (5 > 5)) or ((5 > 0) and true) ===>
( false and not false ) or ( true and true )
( false and true ) or ( true and true )
false or true
true
Переменные логического типа часто используются в качестве «флажков», которые взводятся (устанавливаются в true) в случае наступления во время выполнения программы определенных событий (выход значения переменной за определенный диапазон, считывание из входной последовательности символов определенного символа и т.д.). Значение флажка обычно используется в качестве признака (обычно единственного) описания ситуации выхода из бесконечного цикла (ожидания наступления определенного события). Пример см. в документе «Основы алгоритмизации» там, где рассматривается обработка текста восходящим и нисходящим методами. Там использовалась логическая переменная конец_обработки.
Имеются стандартные функции, возвращающие результат логического типа:
· Odd(аргумент – целый) возвращает True, когда аргумент нечетный, и возвращает False, когда аргумент четный.
· Eoln(аргумент – текстовый файл) возвращает True, если текущим символом строки является символ конца строки.
· Eof(аргумент – файл) возвращает True, если текущий указатель файла установлен на конец файла .
Целые типы
Выделяют целые типы ------------- со знаком – shortint, integer, longint)
------------- без знака - byte, word.
Shortint - занимает 1 байт в памяти со знаком. Диапазон значений: от -128 до +127.
Byte - однобайтовый тип. Данные этого типа только положительные. Диапазон значений: от 0 до 255.
Integer - 2 байта со знаком. Диапазон значений: от -32768 (-215) до +32767 (215-1). Имеется предопределенная константа MaxInt, равная 32767 и определяющая максимальное значение целого числа типа integer.
Word - 2 байта без знака. Диапазон значений: от 0 до 65535.
Longint - занимает 4 байта со знаком. Диапазон значений: - 2 147 483 648 (-231) .. 2 147 483 647 (231-1) .
В Турбо-Паскале предопределены константы MaxLongint, равная 2 147 483 647, и MaxInt, равная 32767.
Для каждого значения этих типов нужно различать:
а) запись значения числа (в одной из систем счисления) в строковом представлении;
б) представление этого значения в виде двоичного кода
в) внутреннее представление (побайтное расположение) этого двоичного (многобайтового) кода в памяти ЭВМ
Рассмотрим пример на то, чем отличаются а) и б) для типов данных shortint и byte.
7 6 5 4 3 2 1 0 -------номера разрядов
26 25 24 23 22 21 20--------веса разрядов
S Shortint
Знаковый разряд (не участвует в выработке значения)
7 6 5 4 3 2 1 0 -------номера разрядов
27 26 25 24 23 22 21 20--------веса разрядов
Byte
старший разряд значения
Для типа shortint знак записывается в самом старшем разряде. А для типа byte этот разряд является частью значения. Поэтому для этих типов в одних тех же 8 битах одно и то же представление в двоичном коде будет соответствовать разным значениям:
Для shortint 11111111 = -1
1 1 1 1 1 1 1 1
Для byte 11111111 = +255
-1 для (shortint) получена потому, что 1 в знаковом разряде соответствует отрицательному числу. Отрицательные (и положительные тоже) числа хранятся в так называемом дополнительном коде. Он получается в 2 приема:
- абсолютное значение числа надо записать в виде двоичного кода и проинвертировать все разряды (0 → 1 1 → 0)
- далее к младшему разряду прибавляется единица. Полученное изображение и будет дополнительным кодом числа (знаковый разряд содержит 0 или 1 и говорит о знаке числа).
Рассмотрим теперь пример на то, чем в) отличается от б). Значения многобайтовых типов (Integer, Word и Longint) хранятся в памяти не так, как пишутся. Они размещаются в памяти, начиная с младших байтов.
Пусть запись целой многобайтовой константы имеет вид:
$ 12 34 - здесь 2 байта.
r slzFvx3ROF20nFImHddz58bpv3XGaYaOPTf27liU8BLdVw/IXjK9XU+jLJ3kQZZNJ0E6qaLgLl+X wW0Zz2ZZdVfeVW+YVj578z5kx1I6VmpnmX5s6YAod/JPpvMkxmDApCfZUTdExBaeqNpqjLSyP7ht feO6RnMYF1rnkfuftB7Rj4U4a+isUYVTbi+lAs3P+vp5cCNwHKaNos8P+jwnMNc+6PQGuYfjtQ3r 1y/l8g8AAAD//wMAUEsDBBQABgAIAAAAIQCzooeN2gAAAAYBAAAPAAAAZHJzL2Rvd25yZXYueG1s TI5BS8QwFITvgv8hPMGbm5qyq9a+LouoF0HYtXpOm9gWk5fSZLv13/s86WkYZpj5yu3inZjtFIdA CNerDISlNpiBOoT67enqFkRMmox2gSzCt42wrc7PSl2YcKK9nQ+pEzxCsdAIfUpjIWVse+t1XIXR EmefYfI6sZ06aSZ94nHvpMqyjfR6IH7o9Wgfett+HY4eYffx8pi/zo0Pztx19bvxdfasEC8vlt09 iGSX9FeGX3xGh4qZmnAkE4VDUGvFTYTNDQiO1ToH0SDkrLIq5X/86gcAAP//AwBQSwECLQAUAAYA CAAAACEAtoM4kv4AAADhAQAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBL AQItABQABgAIAAAAIQA4/SH/1gAAAJQBAAALAAAAAAAAAAAAAAAAAC8BAABfcmVscy8ucmVsc1BL AQItABQABgAIAAAAIQBpsD1UmAIAAHEFAAAOAAAAAAAAAAAAAAAAAC4CAABkcnMvZTJvRG9jLnht bFBLAQItABQABgAIAAAAIQCzooeN2gAAAAYBAAAPAAAAAAAAAAAAAAAAAPIEAABkcnMvZG93bnJl di54bWxQSwUGAAAAAAQABADzAAAA+QUAAAAA " o:allowincell="f"/>
старший младший
байт байт
Этой записи числа в дампе памяти в отладчике будет соответствовать следующий код: 34 12
возрастания адресов слева направо
(совпадает с направлением просмотра)
С данными целых типов могут использоваться несколько стандартных функций и операций:
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 |
1 |
Поразрядное “И” или поразрядное умножение (двухместная операция)
Xi | Yi | Xi and Yi |
Поразрядное “ИЛИ” или поразрядное сложение (двухместная операция)
Xi | Yi | Xi or Yi |
Поразрядное “ИСКЛЮЧАЮЩЕЕ ИЛИ”. Эта операция устанавливает результат, равным единице, при несовпадении соответствующих разрядов (двухместная операция):
Xi | Yi | Xi xor Yi |
Поразрядный сдвиг вправо и влево достигается применением операций (двухместных):
X Shl Y - значение X сдвигается влево на Y разрядов
X shr Y - значение X сдвигается вправо на Y разрядов.
Можно считать, что при выполнении сдвигов мысленная граница разрядной сетки для типа числа (правая или левая) сдвигается на соответствующее число разрядов (вправо или влево):
При сдвиге вправо мысленная правая граница (где заканчивается целая часть числа) перемещается влево;
При сдвиге влево мысленная левая граница (за самым старшим разрядом) перемещается вправо.
Выдвигаемые в направлении сдвига разряды числа, которые пересекают мысленную границу числа, отбрасываются. С противоположной стороны при сдвигах нужное количество разрядов добавляется (оно обычно заполняется нулями).
Нулями всегда заполняются разряды, добавляемые при сдвиге влево или вправо целых положительных чисел. При этом сдвиг влево на N разрядов эквивалентен умножению на 2N, а сдвиг вправо на N разрядов равносилен целочисленному делению (без остатка) на 2N.
Var границы типа Byte x:byte; x = 3 y:byte; 00000011 begin отбрасываем добавляем x := 3; 00 00001100 y := x shl 2; y = x*22 = 12 end. not x = 253 |
При сдвиге вправо отрицательных чисел типов 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) – размер типа в байтах
Перечисляемый тип.
При описании переменной этого типа задается (правда, не напрямую, а косвенно) список ее возможных значений. Этот список задается в виде последовательности имен идентификаторов (каждый идентификатор соответствует одному значению), разделенных запятыми. При этом список заключается в круглые скобки:
Var
0 1 2 3 4 5 ----- в программу вместо имен будут подставлены эти значения
v:(a, b, c, d, e, f);
идентификаторы |
Правила для нахождения значений, соответствующих именам этого списка: самому левому значению соответствует - 0; следующему соответствует 1, и так далее - каждому следующему (слева направо) идентификатору соответствует значение на 1 большее, чем у соседа слева.
Смысл этого типа: как и при использовании простых констант здесь используются имена вместо чисел.
Если булевский тип не был бы введен, то мы его бы ввели таким образом:
type
boolean = (false, true);
Хранятся данные этого типа очень компактно. Если вы перечисляете не более 256 имен, то хранится переменная в одном байте; если >256 но < 65535 то занимает 2 байта. Это действительно компактно, если учесть, что для описания 65535 переменных требуется как минимум 65535 байт. Из вот такой компактной формы хранения этих переменных невозможно выводить значение этих переменных на экран и вводить с клавиатуры. Нельзя написать следующую конструкцию:
write (V);
Однако можно посмотреть значение такой переменной в окне Watch.
Примечание:
Обычной ошибкой в объявлении переменных перечисляемого типа является перечисление не имен, а самих значений, которым эти имена соответствуют.
Var
v: (1, 2, 3, 4, 5, 6); нельзя!
Вопрос: что можно присвоить переменной этого типа – имя (из перечня) или число?
Тип – диапазон
Переменные данного типа объявляются с использованием указания левой и правой границы диапазона.
Общий вид:
Var
v: левая .. правая ;
Примечание 1.
Правая граница должна быть обязательно больше, чем левая.
ПРИМЕР:
Var
v: 1..10; {правильная запись}
v: 10..1; {неправильная запись}
Примечание 2.
Базовым типом для типа-диапазона может быть любой порядковый тип, кроме типа-диапазона. В рассмотренном выше случае базовым является целый тип.
Var
s: ‘a‘..’z’; - базовым является символьный (char) тип.
Примечание 3.
Когда в объявлении типа указывается левая и правая границы, то этим вы указываете компилятору, что возможные значения переменных могут находиться только в этом диапазоне. И компилятор далее будет за этим тщательно следить, включая в программу соответствующие дополнительные команды для проверки.
Примечание 4.
Если включена опция компилятора Range Checking или использована директива компилятора {$R+} в программе, то это заставляет компилятор выполнять проверку выхода значения переменной за указанный диапазон.
Символьный тип
Объявляется следующим образом:
Var
c: char;
Переменная этого типа занимает 1 байт без знака. Диапазон значений от 0 до 255.
Для каждой переменной символьного типа в памяти хранится код символа (порядковый номер символа в таблице кодов ASCII), то есть:
c := ‘ ‘; ------ храниться будет 3210.
c := ‘1’; ------- храниться будет 6110.
Для переменных символьного типа применяются три стандартные функции:
Ord (‘ ’)=32 - возвращает порядковый номер символа в кодировочной таблице ASCII
Pred (‘b’)=’a’ - возвращает значение предыдущего аргументу символа в таблице кода ASCII
Succ (‘a’)=’b’ - возвращает следующий за аргументом по порядку символ в таблице кодов ASCII.
Над переменными символьного типа, кроме трех стандартных функций, могут использоваться операции отношения. Для правильного применения этих операций необходимо учитывать следующие правила:
1) в таблице ASCII символы с изображением цифр расположены так, что символу, которому соответствует большая цифра, соответствует больший номер.
2) в таблице ASCII cимволы с изображением латинских букв расположены в соответствии с их порядком в алфавите.
3) в таблице ASCII вначале расположены все цифры, потом все латинские буквы, а потом все русские.
4) в таблице ASCII вначале расположены все заглавные (прописные) латинские буквы, а потом - все маленькие (строчные).
5) Расстояние между прописной буквой и такой же строчной равно 32.
Для полученных значений переменной символьного типа по коду символа используется функция Chr:
Var c := chr(b)
b: byte;
c: char; b c
begin
b := 25; b := ord(c)
c := Chr(b);
b := Ord(c);
Переменной символьного типа можно присвоить значение следующими способами:
1). c := ‘a’;
2). c:=#61; - символ с кодом 61 в 10 системе счисления
3). c:=#$20; - символ с кодом 32 в 10 системе счисления
Вещественные типы.
Вещественные типы относятся к простым, но не являются порядковыми (5 разновидностей).
Real - занимает 6 байтов
Single - 4
Double - 8
Extended - 10
Comp - 8
Real является стандартным для Паскаля, все остальные относятся к стандартным типам сопроцессора. Из этих четырех типов первые три являются вещественными. Comp “хитрый” целый тип, который совместим со всеми вещественными. Comp введен для того, чтобы с использованием сопроцессора можно было выполнять операцию над длинными целыми числами.
При наличии сопроцессора все операции выполняются над данными в форме типа данных Extended, все остальные значения получаются путем усечения значения типа Extended до нужной ширины в соответствии с заданным типом переменных.
Внутреннее представление переменных вещественных типов подробно рассматривается в курсе «Информатика». Для значений вещественных типов различают 2 части:
- мантисса – нормализованное значение числа;
- порядок – число, показывающее степень, в которую надо возвести мантиссу, чтобы получить истинное значение числа. (из-за нормализации мантиссы).
Real хранится в памяти так:
S | m | e |
Real
возрастание адресов справа налево
S | e | m |
Single
возрастание адресов справа налево
Все нормальные типы сопроцессора (Single, Double, Extended) хранятся таким же образом как Single.
Отличие в форме хранения типа Real приводит к следующему. Основным типом данных при наличии сопроцессора является тип Extended. Если при наличии сопроцессора выбран для представления вещественного значения тип Real, то каждый раз при присваивании значения переменных будет происходить преобразование из Extended в Real и программа будет выполняться значительно медленнее.
Поэтому если сопроцессор имеется (начиная с i486), желательно при большом количестве вычислений с плавающей точкой не использовать тип данных Real, предпочтительнее - Single или Double. Программа будет выполняться значительно (в 2 раза) быстрее.
На Паскале имеется возможность управлять характером работы с этими вещественными типами.
1) разрешить или запретить использовать типы данных сопроцессора:
директивы разрешения (запрета) использования в процессоре типа данных сопроцессора |
{$N+} {$N-} |
Директива {$N+} задает, что разрешено использование всех 5 вещественных типов данных.
Директива {$N-} задает, что разрешено использование только тип Real.
По умолчанию действует {$N-}.
Данная установка перекрывает возможную установку, которая была сделана в среде.
При наличии {$N-} следующая запись будет считаться неправильной:
Var
v: Single;
2) Вы можете управлять, кто должен выполнять действия над данными вещественного типа:
· аппаратными средствами (сопроцессором) с использованием его встроенных команд
· программно (работа с типами данных сопроцессора эмулируется центральным процессором).
Директива {$E+} - разрешает эмуляцию сопроцессора, если его нет, а директива {$E-} - запрещает эмуляцию сопроцессора. По умолчанию действует {$E+}. Слово эмуляция означает моделирование (программное) работы сопроцессора, т.е. воспроизведение реальной работы сопроцессора на его программной модели. Если использовать {$E-}, компилятором будет использован такой код, который нельзя выполнить на машине без сопроцессора.
Возможны следующие комбинации задания директив N и E:
1. {$N+} {$E+}
2. {$N+} {$E-}
3. {$N-} {$E+}
4. {$N-} {$E-}
1-я комбинация соответствует ситуации, когда разрешено использовать типы данных сопроцессора. Если сопроцессора нет, то он будет эмулироваться, если есть - будет сгенерирован код для работы без эмуляции.
2-я комбинация: директива компилятора {$N+} указывает, что будут использованы типы данных сопроцессора, причем работа с ними будет идти без эмуляции.
3-я и4-я: типы данных сопроцессора не используются и поэтому директива {$E}не играет роли.
Как быть, если мы заранее не знаем, есть ли сопроцессор или нет, т.е. можно ли использовать его типы данных без эмуляции или нет? Есть по крайней мере два варианта решения:
1) Если в программе используются все 5 вещественных типов данных, то можно поступить так:
{$IFDEF CPU87} В этом случае компилятор будет сам
{$N+} выбирать (в зависимости от наличия или
{$ELSE} директивы условной компиляции отсутствия сопроцессора) правильную
{$N-} модель генерации кода для работы с
{$ENDIF} вещественными числами
2) если при наличии сопроцессора надо вместо Real использовать Single, то можно записать так:
{$IFOPT N+} {$N+} или {$N-} Здесь мы ввели свой тип float,
type или более сложно ……… под которым в зависимости
real=single; {$IFOPT N+} от наличия сопроцессора пони-
{$ENDIF} type float = single; мается то Real, то Single
{$ELSE}
type float = real;
{$ENDIF}
Var R:float;
Дата добавления: 2016-05-28; просмотров: 2270;