Операции отношения

Для сравнения скалярных величин предусмотрены бинарные операции отношения. Perl отличается от других языков программирования тем, что в нем сравнение числовых и строковых данных осуществляется с использованием разных операций отношения: существует набор операций для сравнения числовых данных и аналогичный набор для сравнения строк. Каждый из этих наборов операций создает соответственно числовой скалярный или строковый скалярный контекст для своих операндов. Все операции отношения, кроме одной — сравнения, возвращают булево значение - «истина» или «ложь» в зависимости от того, удовлетворяют соответствующему отношению операнды или нет. В табл. 4.2 представлен список всех числовых и строковых операций отношения.
Таблица 4.2. Операции отношения
Операция Числовая Строковая Значение
Равенство == eq «Истина», если операнды равны, иначе «ложь»
Неравенство != ne «Истина», если операнды не равны, иначе «ложь»
Меньше < lt «Истина», если левый операнд меньше правого, иначе «ложь»
Больше > gt «Истина», если левый операнд больше правого, иначе «ложь»
Меньше или равно <= le «Истина», если левый операнд больше или равен правому, иначе «ложь»
Больше или равно >= ge «Истина», если правый операнд больше или равен левому, иначе «ложь»
Сравнение <=> cmp 0, если операнды равны; 1, если левый операнд больше правого; -1,если правый операнд больше левого

Числовые операции отношения

Числовые операции отношения сравнивают числовые данные, причем один или оба операнда могут быть заданы строкой, содержащей правильный числовой литерал. Все, что было сказано о преобразовании таких строковых операндов в числовые при изучении арифметических операций, полностью применяется и в случае числовых операций отношения: если не удастся при анализе строки слева направо выделить числовой литерал, то значение такого строкового операнда принимается равным 0. При этом в любом случае, если операнд представлен строкой, не содержащей правильный числовой литерал, при выполнении программы с включенным режимом отображения предупреждающих сообщений будет отображаться сообщение вида
Argument "10 cm" isn't numeric in numeric ge (>=) at ex04-02.pl  line 3.
с указанием нечислового операнда соответствующей операции.
Смысл всех числовых операций отношения полностью соответствует их применению в математике и не вызывает затруднений. Допустимые в Perl числовые операции отношения:
12 > 10; — результат: 1 («истина»);
12.8 < 89.5; — результат: "" («ложь»); 
123 == 89; — результат: "" («ложь»); 
123 != 89; — результат: 1 («истина»);
89.5 <= 89.5; — результат: 1 («истина»);
23 >= 89; — результат: "" («ложь»);
14 <=> 87; — результат: -1 (правый операнд больше левого);
98 <=> 34; — результат: 1 (левый операнд больше правого).
Как видно, применение числовых операций отношения не представляет сложности. Однако следует с большой осторожностью сравнивать вещественные десятичные числа. Если целые числа являются представителями точных чисел, то с вещественными десятичными дело обстоит несколько сложнее. Ведь программа выполняется на компьютере, в котором реализовано всего лишь подмножество множества всех вещественных чисел. Мощность этого подмножества диктуется внутренним представлением вещественных чисел в памяти компьютера. Нельзя представить точно любое вещественное число, так как в представлении вещественных чисел в компьютере мантисса (значащие цифры числа) ограничена некоторым вполне определенным количеством цифр. Это количество цифр в мантиссе представления вещественных чисел зависит от аппаратной части самого компьютера. Так, в компьютере с 32-разрядным процессором вещественные числа с удвоенной точностью содержат всего лишь 16 значащих цифр. Второй аспект в представлении вещественных чисел связан с переводом дробной части числа из десятичной системы счисления в двоичную — ту, с которой работает большинство современных компьютеров. При переводе вещественных чисел в двоичную систему счисления неизбежны погрешности, так как некоторые конечные десятичные дроби в двоичной системе представляются бесконечными, что и приводит к ошибкам округления с учетом ограниченности мантиссы.
Все сказанное о представлении вещественных чисел следует помнить, когда мы сравниваем вещественные числа. Особенно это относится к операции сравнения на равенство. Рассмотрим простой сценарий листинга 4.1.
Листинг 4.1. Ошибки округления
#!perl -w
$real1 = 0.7,	# переменная $rеаl1 равна 0.7
$real2 = 10+0.7-10; # переменная $rеаl2 равна 0.7
# Сравнение числовых переменных $real1 и $rеаl2
print("$real1 равно $real2") if ($real1 == $real2);
По нашим представлениям, этот сценарий должен напечатать строку 0.7 равно 0.7, так как обе переменные $real1 и $real2 содержат одно и то же число 0.7. Попробуем выполнить этот сценарий. К нашему удивлению, он ничего печатать не будет. Это говорит о том, что значения двух проверяемых переменных не равны между собой. Разгадка лежит в операторе вычисления значения переменной $rеаl2. При выполнении в выражении операций сложения в том порядке, в котором они заданы, результат будет равен 0.699999999999999. Это хотя и очень близкое к 0.7 число, но все-таки ему не равное. Поэтому-то результатом вычисления нашей операции сравнения является «ложь», что и приводит к невыполнению операции печати. Если изменить порядок вычисления значения переменной $real 2 на 10-10+0.7, то наш сценарий будет работать так, как мы и ожидали, так как в этом случае 0 будет складываться с 0.7, что даст желаемый результат 0.7.
Конечно, приведенный пример тривиален, однако достаточно показателен, чтобы увидеть сложности, которые таит в себе компьютерная арифметика с вещественными числами.
СОВЕТ При сравнении на равенство двух вещественных чисел рекомендуется ввести погрешность и сравнивать абсолютную величину разности этих двух чисел с величиной веденной погрешности. Например, так:
abs($real1 - $real2) <= 0.000001;

Строковые операции отношения

Сравнение строк осуществляется посимвольно слева направо, причем в основу упорядочения символов положен их ASCII-код: символ с меньшим значением ASCII-кода предшествует символу с большим ASCII-кодом.
Таким образом, алгоритм сравнения строк выглядит представленным ниже образом.
  1. Проверяются на равенство ASCII-коды первых символов строк.
  2. Если они равны, то проверяются на равенство ASCII-коды следующих символов.
  3. Процесс останавливается, если ASCII-коды соответствующих символов не равны.
В случае строк, содержащих разное количество символов, в конец строки с меньшим числом символов добавляются символы с нулевым ASCII-кодом.
ВНИМАНИЕ В Perl пробельные символы в строке (сам пробел \040, символ табуляции \t и символ новой строки \n) являются значимыми.
Приведем некоторые случаи сравнения строк.
"A" lt "а";  — результат: «истина» (код "А" — \101, код "а" — \141);
"a" lt "aa"; — результат: «истина» (к строке "а" добавляется символ с кодом \000, 
               который меньше кода \141 второго 
               символа "а" строки правого операнда);
"a" lt "а";  — результат: «истина» (к строке "а" добавляется символ с кодом \000,
               который меньше кода \040 замыкающего пробела 
               строки правого операнда);
12 lt 9; — результат: «истина» (код "1" — \061, код "9" — \071); 
"9" eq "09"; — результат: «ложь» (код " " — \040, код "0" — \060).
Две последние операции отношения показывают, что строковое сравнение числовых данных не совпадает с числовым сравнением. В предпоследней операции сравнения числовые операнды преобразуются к строковым, как требует контекст операции lt, а затем осуществляется сравнение строк. Результат отличается от числового сравнения, в котором был бы получен ответ «ложь». Если в последней операции сравнения строковое сравнение заменить на числовое, то результатом будет «истина», так как оба строковых операнда в числовом скалярном контексте представляют одно и то же число 9.
В Perl, по аналогии с языком С, определен большой набор директив компилятора, или прагм, которые предназначены для задания определенного поведения компилятора при транслировании программы. Например, можно указать компилятору в определенной части программы использовать целочисленную арифметику вместо применяемой по умолчанию арифметики вещественных чисел удвоенной точности или отменить при работе со строками формат Unicode (UTF-8) представления символов и вернуться к обычному байтовому их представлению. Для задания директивы компилятору используется ключевое слово use, после которого указывается требуемая директива. Отменить действие директивы можно с помощью ключевого слова no с последующим заданием имени директивы. Действие директивы компилятора распространяется на область программы, заключенную между указанными операциями use и no:
#!perl  -w
# используется арифметика вещественных чисел
use integer;
# используется целочисленная арифметика
no integer: #отмена целочисленной арифметики
# снова используется арифметика вещественных чисел
В данном разделе мы привели небольшое введение в директивы компилятора исключительно из-за прагмы locale, которая влияет на выполнение строковых операций отношения. Эта прагма позволяет использовать локальные установки операционной системы, связанные с упорядочением символов, отображением времени и дат, а также числовых данных, которые влияют на выполнение строковых операций отношения lt,1e, gt, ge и cmp, встроенной функции sort( ), которая использует в своем встроенном алгоритме операцию сравнения строк cmp, если программист не определил иной алгоритм упорядочения, и на вычисление регулярных выражений.
ВНИМАНИЕ Применение прагмы locale не влияет на выполнение строковых операций отношения eq и ne.
По умолчанию, как отмечалось ранее, упорядочение символов осуществляется на основе их ASCII-кода. При использовании директивы компилятора use locale упорядочение символов осуществляется на основе кодов используемой в данный момент таблицы символов операционной системы. Например, при работе в русской версии MS Windows по умолчанию используется таблица кодировки символов 1251. Прагма locale переключит компилятор perl таким образом, что в указанных выше операциях сравнения строк будет применяться кодировка именно этой таблицы.

Следующая страница Содержание главы


Реклама