программирование, создание программ, учебник Delphi, учебник по программированию, бейсек, делфи, си, паскаль
 
 
 

 

Операции и выражения


Арифметические операции


Язык программирования, предоставляя возможность определения разнообразных типов данных, должен обеспечивать их обработку, т. к. его основной целью является реализация алгоритмов обработки данных. Выполнение допустимых действий над данными осуществляется с помощью набора определенных в языке программирования операций. Операция — это выполнение определенного действия над операндами, результатом которого является новое значение. С точки зрения математики операцию можно рассматривать как некую функцию, которая по заданным переменным (операндам) вычисляет новое значение. Все знают со школьной скамьи четыре основных арифметических действия, выполняемых над числами: сложение (+), вычитание (-), умножение (*) и деление (/). Эти действия (операции) мы всегда выполняем над двумя числами (операндами), получая в результате новое число. Язык программирования определяет не только арифметические операции над числовыми данными, но и операции, применимые к другим допустимым типам данных. Это могут быть операции над строками, массивами и т. д. Важно только одно, что есть операция, определяемая своим знаком, и есть участвующие в ней операнды, в совокупности позволяющие получить (вычислить) новое значение, которое может принадлежать к одному из допустимых типов. В качестве операндов можно использовать литералы, переменные и выражения, представляющие собой комбинации основных операций. Общий синтаксис операции можно представить следующим образом:
операнд знак_операции операнд
Для некоторых операций один из операндов может быть опущен. В этом случае операция называется одноместной или унарной, например, вычисление противоположного по знаку значения операнда -$т. Если в операции участвуют два операнда, то операция называется двуместной или бинарной. Практически все допустимые операции являются унарными или бинарными, но в некоторых современных языках программирования определена од-на-единственная условная тернарная операция, требующая три операнда. Значением этой операции является второй или третий операнд, в зависимости от истинности и ложности первого:
операнд_1 ? операнд_2 : операнд_3

Синтаксически выражение представляется в виде последовательности операндов и знаков операций, которая обычно интерпретируется слева направо учетом порядка старшинства операций, т. е. правил, определяющих, в какой последовательности выполняются присутствующие в выражении операции. Для изменения порядка выполнения используются круглые скобки. Результатом обработки интерпретатором выражения является некоторое вычисленное значение, которое используется в других конструкциях языка, реализующих алгоритм обработки данных.
В этой главе подробно рассматриваются операции языка Perl и их использование при конструировании выражений. В языке Perl определено несколько десятков операций. Их можно сгруппировать по типу выполняемых действий (арифметические, побитовые, логические, отношения, присваивания), на какие данные они воздействуют (строковые, списковые, файловые), и не относящиеся ни к одному из перечисленных типов (операции запятая, ссылки, разыменования и выбора). Следуя именно такой классификации операций языка Perl, мы и познакомим с ними нашего читателя. Одни операции будут разобраны подробно, о других мы только дадим общее представление, отнеся более детальное описание в другие главы нашей книги.  
Все арифметические операции можно разбить на три группы: бинарные, унарные и увеличения/уменьшения. Их основное назначение — выполнить определенные вычисления над числовыми данными, но во всех арифметических операциях в качестве операндов могут выступать и строковые данные, причем не обязательно, чтобы они конвертировались в числовые данные.

Бинарные арифметические операции
Бинарные арифметические операции — это известные всем четыре арифметических действия: сложение (+), вычитание (-), умножение (*) и деление (/), к которым добавляются еще два: остаток от деления двух целых чисел (%) и возведение в степень (**). Примененные к числовым данным или строковым, которые содержат .правильные литералы десятичных чисел, они выполняют соответствующие арифметические действия (пример 4.1).
3.14 + 123; # Результат: 126.14

"3.14" + "123"; # Результат: 126.14

"3.14" + 123; # Результат: 126.14

"3.14" * 10; # Результат: 31.4

300 - 200; # Результат: 100

300 / 200; # Результат: 1.5

3 % 2; # Результат: 1

2 ** 3; . # Результат: 8

(-2) ** 3; # Результат: -8 '

2 ** (-3); # Результат: 0.125

2.5 ** 1.5; # Результат: -23.95284707521047

Как видим, бинарные арифметические операции "работают" именно так, как мы привыкли их использовать в обычных арифметических вычислениях в нашей повседневной жизни.

Замечание
Если операнд в операции получения остатка от деления целых чисел (%) является вещественным числом с дробной частью, то он преобразуется к целому простым отбрасыванием дробной части, после чего операция выполняется над целыми числами.
Замечание
Нельзя возводить отрицательное число не в целую степень. Если такое случается, то интерпретатор не выдает никакой ошибки, но результатом такой операции является нуль: (-2.5) ** (1.3) = о.
В качестве операндов бинарных арифметических операций можно использовать строки, не содержащие правильные числовые литералы. В этом случае интерпретатор попытается выделить, начиная с первого символа, из содержимого строки число и использовать его в качестве соответствующего операнда заданной операции. Если не удается выделить правильный числовой литерал, то операнд принимает значение, равное о. Подобные ситуации демонстрируются в примере 4.2.
"3fl4" •+ "12-30"; # Результат: 15 ("3" + "12")

"а!20" + "12-30"; # Результат: 12 ("О" + "12")

."а!20" + "-0012-30"; # Результат: -12 ("О" + "-12")

Замечание
Если установить режим отображения предупреждающих сообщений интерпретатора (ключ -w), то при попытке использовать в бинарных арифметических операциях строки, не содержащей правильные числовые литералы, будет отображено сообщение вида:
Argument "al20" isn't numeric in add at D:\EXAMPLE1.PL line 2.

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

@m = (2, 4, 6, 8, 10) ;

%ml = ( 1 => "а", 2 => "Ь"};

$n = 100;

$n + @m; # Результат: 105 (100 + 5)

@m + %ml; # Результат: 7 (5+2)

Замечание
В скалярном контексте хеш-массив принимает строковое значение, состоящее из числа использованных участков записей в хеш-таблице и числа выделенных участков записей, разделенных символом "/" (см. главу 3). Используемое в арифметических операциях число получается выделением из этой строки числового литерала, который как раз и соответствует количеству использованных в хеш-таблице записей.
Унарные арифметические операции
В языке Perl есть только две унарные арифметические операции (+) и (-). Унарный плюс +, примененный к данным любого типа, представленным литералами или своими переменными, не имеет никакого семантического эффекта. Он полезен перед выражением в круглых скобках, стоящим непосредственно после имени функции, если необходимо чисто визуально акцентировать тот факт, что функция фактически является списковой операцией.

Унарный минус (-) выполняет арифметическое отрицание числового операнда. Это означает, что если число было отрицательным, то оно станет положительным, и наоборот. Если операндом является идентификатор, то результатом выполнения этой операции будет строка, состоящая из символа "-", за которым следует идентификатор. Если операндом является строка, начинающаяся с символа минус или плюс, то результатом также будет строка, в которой минус заменен на плюс и наоборот. Для строк, не начинающихся с плюса или минуса, операция унарного минуса добавляет его первым символом в строку. Все перечисленные случаи употребления унарного минуса показаны в примере 4.4.

-'12.09'; # Результат: -12.09

-(-12.09);•# Результат: 12.09

-id; # Результат: '-id'

-'+id"; # Результат: '-id'

-"-id"; # Результат: "+id"

-'а!20'; # Результат: '-а!20'

Операции увеличения и уменьшения
Операции увеличения (++) и уменьшения (--) аналогичны таким же операциям в языке С. (Авторы языка Perl не скрывают, что они многое заимствовали из этого языка.) Результат этих операций зависит от того, стоят ли они перед (префиксная форма) или после переменной (постфиксная форма). При использовании префиксной формы они, соответственно, увеличивают или уменьшают числовое значение переменной на единицу до возвращения значения. Постфиксная форма этих операций изменяет числовое значение переменной после возвращения ими значения. Действие этих операций на числовые переменные иллюстрируется примером 4.5 (операторы фрагмента программы выполняются последовательно).
$n = 10.7; # Начальное значение

$infl = —$n; # Результат: $infl = 9.7и$n=9.7
$inf2 = ++$n; # Результат: $inf2 = 10.7 и $n = 10.7
$postl = $n--; # Результат: $postl = 10.7 но $n= 9.7
$post2 = $n++; # Результат: $post2 = 9.7 но $n= 10.7

Операция увеличения (префиксная и постфиксная), примененная к переменной, содержащей строку определенного вида, выполняется несколько необычно. Если строка состоит только из латинских букв, то возвращаемым значением операции увеличении будет строка, в которой последняя буква заменена на следующую по порядку букву алфавита, причем строчная заменяется строчной, а прописная прописной. Если строка завершается идущими подряд буквами "z" или "z", то все они заменяются соответственно на "а" или "А", а стоящая перед ними в строке буква заменяется на следующую букву алфавита. Если вся строка состоит из букв "z" и "z", то кроме замены этих букв в соответствии с предыдущим правилом, перед ними добавляется строчная или прописная буква "а" в зависимости от того, строчная или прописная буква "z" стояла первой в строке.

Аналогичные действия осуществляются, если строка завершается последовательностью цифр: последняя цифра увеличивается на единицу. Если строка завершается идущими подряд цифрами 9, то все они заменяются на о, а примыкающий к ним символ "увеличивается" на единицу: для буквы он переходит в следующий по алфавиту, а для цифры в следующую по порядку цифру. Если последовательность целиком состоит из девяток, то все они заменяются на нули, перед которыми добавляется единица. Префиксная и постфиксная формы операции действуют как обычно. Несколько иллюстраций этих операций представлены в примере 4.6.

$s = "abc"

$sl = ++$s; # Результат: $sl = "abd"

$s = "abC";

$sl = ++$s; # Результат: $sl = "abD"

$s = "abz";

$sl = ++$s; # Результат: $sl = "аса"

$s = "abzZz";

$sl = ++$s; # Результат: $sl = "acaAa"

$s = "ab09";

$sl = ++$s; # Результат: $sl = "ablO"

$s = "99"; .

$sl = ++$s; # Результат: $sl = "100"

Замечание
Операция уменьшения (—) работает со специальными строками так же, как и с обычными. Осуществляется попытка выделить числовой литерал, начиная с первого символа. Если такое оказывается возможным, то числовое значение строки приравнивается выделенному числовому литералу, если нет — ее значение считается равным 0. После этого применяется операция уменьшения к вычисленному числовому значению строки
Операции конкатенации и повторения
Бинарная операция конкатенации, или соединения объединяет два строковых операнда в одну строку. Знаком этой операции служит точка ".":
"one_string"."two_string"; # Результат: "one_stringtwo_string"

В новой строке содержимое первого операнда и содержимое второго операнда соединяются без пробела между ними. Обычно эта операция используется для присваивания переменной некоторого нового значения. Если необходимо соединить две или более строки со вставкой пробелов между ними, то следует воспользоваться операцией join (см. гл. 10 "Работа со строками"). Можно, однако, для соединения строк со вставкой пробела (или любого другого символа между ними) воспользоваться свойством подстановки значения скалярной переменной в строку, ограниченную двойными кавычками: $sl = "one_string"; $s2 = "two_string"; $s = "$sl $s2"; # Значение $s: "one_string two_string"

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

$sl = "one";

$s2 = "two";

$s3 = "three";

$s = $sl.$s2.$s3; # Значение $s: "onetwothree"

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

$nl = 23.5;

$n2 = Зе01;

$n = $nl.$n2; t Значение $n: "23.530"

$n = 23.5.3е01; # Значение $n:'"23.530"

Заметим, что последний оператор выглядит несколько экзотично и его семантика не определяется с первого взгляда.

Для работы со строками в языке Perl предусмотрена еще одна операция — повторение строки х (просто символ строчной буквы "х"). Эта бинарная операция создает новую строку, в которой строка, заданная левым операндом, повторяется определяемое правым операндом количество раз:

"аА" х 2; # Результат: "аАаА"

10.0 х "3"; # Результат: "101010"

101е-1 х 3; # Результат: "101010" $n = 010;

$n х 2; # Результат: "88"

10.1 х 3.9; # Результат: "10.110.110.1"

"101е-1" х 2; # Результат: "101е-1101е-1"

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

Эта операция удобна, если надо напечатать или отобразить на экране монитора повторяющийся символ или последовательность символов. Например, следующий оператор выведет на экран монитора строку, целиком состоящую из символов подчеркивания: print "_" х 80;

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

(1) х 3; # Результат: (1, 1, 1) (1, 2) х 2; # Результат: (1, 2, 1, 2)

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

@аггау = ("а", "b") х 2; # Результат: Оаrrау = ("а", "Ь", "а", "Ь") @аrrау = ("а") х 3; # Результат: @аrrау = ("а", "а", "а")

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

@keys = ( one, two, three); # Определение ключей хеш-массива. @hash{@keys} = ("а") х @keys; # Инициализация значений хеш-массива.

В последнем операторе присваивания в правой части массив скаляров @keys используется в списковом контексте и представляет список своих значений, тогда как в левой части он используется в скалярном контексте и имеет значение, равное числу своих элементов.

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

$nx$m;

интерпретатор определит, что в ней идут подряд две переменные $nх и $m, a не операция повторения содержимого переменной $п, что приведет к синтаксической ошибке.
Операции отношения
Для сравнения скалярных данных или значений скалярных переменных язык Perl предлагает набор бинарных операций, вычисляющих отношения равенства, больше, больше или равно и т. п. между своими операндами, поэтому эту группу операций еще называют операциями отношения. Для сравнения числовых данных и строковых данных Perl использует разные операции. Все они представлены в табл. 4.1.
Таблица 4.1. Операции отношения

Результатом операций отношения (кроме последней сравнения) является Истина, значение 1, или Ложь, пустая строка "".

Замечание
Значение истина в арифметических операциях интерпретируется как число 1, а в строковых как строка "1". Значение ложь в арифметических операциях интерпретируется как число 0, а в строковых как пустая строка " ".
Числовые операции отношения
Числовые операции отношения применяются к числовым данным, причем один или оба операнда могут задаваться строкой, содержащей правильное десятичное число. Если в числовых операциях отношения какой-либо из операндов задан строкой, содержимое которой не представляет правильное десятичное число, то его значение принимается равным о и отображается предупреждение о некорректном использовании операнда в числовой операции отношения (если включен режим отображения предупреждений интерпретатора Perl). Смысл операций отношения для числовых данных соответствует обычным математическим операциям сравнения чисел (пример 4.7).
123 > 89; # Результат: 1 (истина)

123 < 89; # Результат: "" (ложь)

123 <= 89; # Результат: "" (ложь)

89 <= 89; # Результат: 1 (истина)

23 >= 89; # Результат: "" (ложь)

23 <=> 89; # Результат: -1 (правый операнд больше левого)

89 <=> 23; # Результат: 1 (правый операнд больше левого)

Применение числовых операций сравнения не представляет сложности, однако при сравнении на равенство десятичных чисел с плавающей точкой могут проявиться эффекты округления, связанные с ограниченным количеством значащих цифр в мантиссе представления действительных чисел в компьютере и приводящие к "неправильной", с точки зрения пользователя работе операций сравнения. Пример 4.8 иллюстрирует подобную ситуацию.
#! peri -w
$z = 0.7;

$zz =• 10+0.7-10; # Переменная $zz содержит число 0.7

# Печать строки "z равно zz", если равны значения переменных $z и $zz print "z равно zz\n" if ($z == $zz);

При попытке выполнить пример 4.8 мы с удивлением обнаружим, что наша программа ничего не напечатает. В чем же дело? Разгадка лежит в операторе вычисления значения переменной $zz. При выполнении арифметических операций в результате ошибок округления получается значение 0.699999999999999 (можете вставить оператор печати переменной $zz и убедиться в этом), хотя и близкое к 0.7, но не равное ему в точности. Следовательно, операция сравнения отработала верно!

Совет
Не используйте операцию сравнения на равенство вещественных чисел, ее результат может не соответствовать ожидаемому с точки зрения математики. Если необходимо проверить равенство двух вещественных чисел, то лучше сравнивать абсолютное значение их разности с некоторым очень маленьким числом (в зависимости от требуемой точности):
abs($a-$b) <= 0.00000001; # Проверка равенства
 
Строковые операции отношения
Сравнение строковых данных базируется на их упорядочении в соответствии с таблицей кодов ASCII, т. е. символ с меньшим кодом ASCII предшествует символу с большим кодом. Сравнение строк осуществляется посимвольно слева направо. Это означает, что если равны первые символы строк, то сравниваются вторые и если они равны, то сравниваются третьи и т. д. Причем, если строки разной длины, то в конец строки меньшей длины добавляется недостающее для равенства количество символов с кодом о. Следует отметить, что в отличие от некоторых других языков программирования в Perl замыкающие строку пробельные символы являются значимыми при сравнении строк. В примере 4.9 показаны сравнения строк, иллюстрирующие изложенные правила.

Обратим внимание на две последние операции сравнения строковых литералов. Содержимое их операндов может быть преобразовано в правильные числа, и поэтому к ним применимы аналогичные числовые операции отношения. Однако их результат будет существенно отличаться от результата выполнения строковых операций отношения. При использовании операции < в предпоследнем выражении результат будет Ложь, а если в последнем выражении применить операцию ==, то результат будет Истина. Об этом всегда следует помнить, так как Perl автоматически преобразует символьные данные в числовые там, где это необходимо.
Логические операции
Рассмотренные в предыдущем параграфе операции сравнения используются в условном операторе if (о нем и других операторах Perl в следующей главе) для организации ветвления в программе. Однако, иногда желательно проверять одновременно результаты нескольких операций сравнения и предпринимать соответствующие алгоритму действия. Можно подобную ситуацию запрограммировать с помощью вложенных операторов if, а можно в одном операторе использовать сложное выражение, результатом вычисления которого будет, например, истинность двух или более каких-либо операций сравнения. Для формирования подобных проверок и служат логические операции языка Perl.

В языке определены бинарные операции логического сравнения | 1 (ИЛИ), s & (И) и унарная операция логического отрицания !. Их действие аналогично действию соответствующих математических операций исчисления предикатов. Результатом операции | | (логическое ИЛИ) является Истина, если истинен хотя бы один из операндов, в остальных случаях она возвращает Ложь (остальные случаи представляют единственный вариант, когда оба операнда ложны). Операция логического И && возвращает в качестве результата Истину, только если оба операнда истинны, в противном случае ее результат Ложь. Операция логического отрицания ! работает как переключатель: если ее операнд истинен, то она возвращает Ложь, если операнд имеет значение Ложь, то ее результатом будет Истина.

Замечание
В языке Perl нет специальных литералов для булевых значений Истина и Ложь. В качестве значения Истина принимается любое скалярное значение, не равное нулевой строке "" или числу 0 (а также его строковому эквиваленту "О"). Естественно, нулевая "" строка и о (вместе с его строковым эквивалентом "О") представляют значение Ложь.
Начиная с Perl 5.001, в язык были введены логические операции or, and, not и хог. Первые три полностью аналогичны логическим операциям | |, && и !, тогда как операция хог реализует исключающее ИЛИ:

Истина хоr Истина = Ложь

Истина хоr Ложь = Истина

Ложь хоr Истина = Истина

Ложь хоr Ложь = Ложь

Единственное отличие этих логических операций от рассмотренных ранее заключается в том, что они имеют наименьший приоритет при вычислении сложных выражений.
В Perl вычисление логических операций ИЛИ и И осуществляется по "укороченной схеме". Это непосредственно связано со смыслом этих операций. Если при вычислении операции ИЛИ определено, что значение ее первого операнда Истина, то при любом значении второго операнда результатом всей операции будет Истина, поэтому нет смысла вообще вычислять второй операнд. Аналогично для операции логического И: если значение первого операнда Ложь, то результат всей операции Ложь вне зависимости от значения второго операнда. В отличие от операций отношения, результатом которых может быть о (или пустая строка "") или 1, соответствующие булевым значениям Ложь и Истина, результатом логических операций является значение последнего вычисленного операнда. Пример 4.10 иллюстрирует вычисление логических операций.

$opl = 0; $ор2 = "s"; $орЗ = ""; $ор4 = 25; $ор5 = "0";
$ор4 II $ор2; # Результат: истина. Значение: 25.
$ор2 I| $ор4; # Результат: истина. Значение: "s".
$opl && $ор2; # Результат: ложь. Значение: 0.
$ор2 && $ор4; # Результат: истина. Значение: 25.
!$ор2; # Результат: ложь. Значение: "".
not $орЗ; # Результат: истина. Значение: 25.
$ор4 and $op5; # Результат: ложь. Значение: "".

Свойство логических операций языка Perl вычисляться по "укороченной схеме" можно использовать для управления некоторыми исключительными ситуациями, возникающими в программе в процессе вычислений. Например, можно достаточно элегантно избежать деления на нуль с помощью операции логического ИЛИ:

($х = 0) II ($т = 1/$х);

При вычислении результата этой операции сначала вычисляется левый операнд, который сравнивает значение переменной $х с нулем. Если это значение действительно равно нулю, то результатом операции сравнения будет Истина, а поэтому второй операнд операции логического ИЛИ не вычисляется, так его значение не влияет на результат выполнения логической oпeрации, и не возникает ситуации деления на нуль. Если значение переменной $х не равно нулю, то результатом вычисления первого операнда операции | | будет Ложь, и обязательно будет вычисляться ее второй операнд, в котором осуществляется деление на не равную нулю переменную $х.
Побитовые операции
Данные в компьютере представляются в виде последовательности битов. В языке Perl определены бинарные операции побитового логического сравнения целых чисел и строк: & (И), | (ИЛИ) и л (исключающее ИЛИ), а также унарная операция логического отрицания ~. Результат их вычисления зависит от того, к данным какого типа они применяются: числовым или строковым. Эти операторы различают числовые данные и строки, содержимое которых может быть преобразовано в число.
Кроме логических операций побитового сравнения, две операции сдвигают влево («) и вправо (») биты в представлении целых чисел. Эти операторы не работают со строками.

Числовые операнды
Если хотя бы один операнд в бинарных побитовых операциях является числом, то содержимое второго операнда также должно быть числом. Операнд, являющийся строкой символов, преобразуется в числовое значение. В случае несоответствия содержимого строки десятичному числу ее значение принимается равным о и отображается предупреждающее сообщение, если установлен соответствующий режим работы интерполятора. Все числовые операнды преобразуются к целым числам простым отбрасыванием дробной части, никакого округления не происходит.
Чтобы понять сущность побитовых операций над числовыми данными, необходимо представлять, как хранятся в программе целые числа. При задании чисел мы можем использовать одно из трех представлений: десятичное, восьмеричное или шестнадцатеричное. Однако в компьютере числа не хранятся ни в одном из указанных представлений. Они переводятся в двоичные числа — числа с основанием 2, цифры которых и называются битами. Двоичные числа представляют собой запись чисел в позиционной системе счисления, в которой в качестве основания используется число 2. Таким образом, двоичные цифры, или биты, могут принимать значения только о или 1. Например, десятичное число ю, переведенное в двоичное, представляется в виде loio. Для обратного перевода этого числа в десятичную форму представления следует, в соответствии с правилами позиционной системы счисления, произвести следующие действия:

1 * (2**3) + 0 * (2**2) + 1 * -(2**1) + 0 * (2**0)

Язык Perl гарантирует, что все целые числа имеют длину 32 бит, хотя на некоторых машинах они могут представляться и 64 битами. Именно с двоичными представлениями целых чисел и работают все побитовые операции, преобразуя и отрицательные, и положительные числа к целому типу данных.

Операция & побитового логического И сравнивает каждый бит правого операнда с соответствующим битом левого операнда. Если оба сравниваемых бита имеют значение 1, то соответствующий бит результирующего значения операции устанавливается равным 1, в противном случае значением бита результата будет о. В качестве примера рассмотрим следующее выражение

45.93 & 100

Прежде всего, правый операнд преобразуется к целому 45, двоичное представление которого будет

00000000000000000000000000101101

Двоичное представление левого операнда юо будет иметь вид

00000000000000000000000001100100

Результатом побитового логического И будет следующая последовательность битов

00000000000000000000000000100100

Она соответствует десятичному целому числу 36. Следовательно, значением выражения 45.93 & юо будет целое число 36.

Замечание
В этом примере мы специально использовали 32-битное представление целых чисел, хотя для бинарных побитовых операций лидирующие нули не имеют значения. Они существенны только при операциях побитового логического отрицания и сдвигов.
При побитовой операции логического ИЛИ | бит результата устанавливается равным 1, если хотя бы один из сравниваемых битов равен 1. Операция побитового логического ИЛИ для тех же двух чисел

45.93 | 100

даст результат равный юэ, так как при применении побитового логического ИЛИ к операндам

00000000000000000000000000101101 (десятичное 45)

И

00000000000000000000000001100100 (десятичное 100)

дает следующую цепочку битов

00000000000000000000000001101101 (десятичное 109:

2**6+2**5+2**3+2'**2+2**1)

Побитовое исключающее ИЛИ при сравнении битов дает значение \ тогда, когда точно один из операндов имеет значение равное 1. Следовательно, 1 ^ 1=о и о ^ о=о, в остальных случаях результат сравнения битов равен о. Поэтому для тех же чисел результатом операции будет десятичное число 73.

Операция логического отрицания ~ является унарной и ее действие заключается в том, что при последовательном просмотре битов числа все значения о заменяются на 1, и наоборот. Результат этой операции существенно зависит от используемого количества битов для представления целых чисел. Например, на 32-разрядной машине результатом операции ~1 будет последовательность битов

11111111111111111111111111111110

представляющая десятичное число 42949б7294=2 31 +2 30 +...+2 1 , тогда как на 16-разрядной машине эта же операция даст число б534=2 31 +2 30 +...+2 1 .

Бинарные операции побитового сдвига осуществляют сдвиг битов целого числа, заданного левым операндом, влево («) или вправо (») на количество бит, определяемых правым целочисленным операндом. При сдвиге вправо недостающие старшие биты, а при сдвиге влево младшие биты числа дополняются нулями. Биты, выходящие за разрядную сетку, пропадают. Несколько примеров операций сдвига представлено ниже:

# Битовое представление числа 22: (00000000000000000000000000010110)

22 » 2 # Результат: (00000000000000000000000000000101) = 5

22 << 2 # Результат: (00000000000000000000000001011000) = 88

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

00000000000000000000000000000001 # положительное число 1 111111111111111111111111111111Ю # обратный код числа 1 11111111111111111111111111111111 # добавляем к младшему разряду 1

# и получаем представление числа -1

Именно с этим кодом числа -i будут работать все побитовые операции, если оно будет задано в качестве операнда одной из них.

Внимание
В языке Perl, как отмечалось в гл. 3, в арифметических операциях используется представление всех чисел в виде чисел с плавающей точкой удвоенной точности. Там же говорилось, что целое число можно задавать с 15 значащими цифрами, т.е. максимальное положительное целое число может быть 999 999 999 999 999. Но это число не имеет ничего общего с представлением целых чисел в компьютере, для которых может отводиться 64, 32 или 16 битов, в зависимости от архитектуры компьютера. Во всех побитовых операциях можно предсказать результат только если операндами являются целые числа из диапазона -2 32 -1. . 2 32 -1, так как ясен алгоритм их представления. Вещественные числа, не попадающие в этот диапазон, преобразуются к целым, но алгоритм их преобразования не описан авторами языка.

Строковые операнды
Если оба операнда являются строковыми литералами или переменными, содержащими строковые данные, то операции побитового логического сравнения сравнивают соответствующие биты кода каждого символа строки. Для кодирования символов используется таблица ASCII-кодов. Если строки разной длины, то при сравнении полагается, что строка меньшей длины содержит необходимое число недостающих символов с восьмеричным кодом \ооо. Например, результатом сравнения двух строк "++" и "з" с помощью операции | побитового логического ИЛИ будет строка ",-+". Операнды этой операции представляются следующими битовыми последовательностями (каждый символ представляется 8 битами):
00101011 00101011 # Восьмеричный код символа "+" равен 053. 00110011 # Восьмеричный код символа "3" равен 063.

Вторая строка дополняется восемью нулевыми битами и последовательно для каждой пары соответствующих бит двух строк одинаковой длины выполняется операция логического ИЛИ. Результатом выполнения этой процедуры является битовая последовательность

00111011 00101011

При ее интерпретации как строки символов получается последовательность двух символов с восьмеричными кодами 07 3 и 053, которые соответствуют символам ";" и "+"

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

45.93 I 100 # Результат: число 109.

"45.93" I 100 # Результат: число 109.

45.93 I "100" # Результат: число 109.

"45.93" I "100" # Результат: строка "55>93".

В первых трех операциях этого примера строки преобразуются в числа, а потом выполняется соответствующая операция побитового логического ИЛИ двух чисел.

Выполнение операции побитового логического отрицания ~ для строки ничем не отличается от соответствующей операции отрицания для чисел с той лишь разницей, что применяется она к битовому представлению символов строки:

~"1" # Результат: "+".
~"ab" t Результат: "ЮЭ".
Операции присваивания
Присваивание переменной какого-либо значения, определенного литералом, или присваивание одной переменной значения другой переменной является наиболее часто выполняемым действием в программе, написанной на любом языке программирования. В одних языках это действие определяется с помощью оператора, а в других — с помощью операции. Отличие заключается в том, что в языках, где присваивание является операцией, оно может использоваться в выражениях как его составная часть, так как любая операция вычисляет определенное значение, тогда как оператор всего лишь производит действие. В языке Perl присваивание является операцией, которая возвращает правильное lvalue. Что это такое, мы разъясним буквально в следующих абзацах.
Операция присваивания =, с которой читатель уже немного знаком, является бинарной операцией, правый операнд которой может быть любым правильным выражением, тогда как левый операнд должен определять область памяти, куда операция присваивания помещает вычисленное значение правого операнда. В этом случае и говорят, что левый операнд должен быть правильным lvalue (от английского left value — левое значение). А что мы можем использовать в программе для обозначения области памяти? Правильно, переменные. Следовательно, в качестве левого операнда операции присваивания можно использовать переменную любого типа или элемент любого массива. (В языке Perl существуют и другие объекты, которые можно использовать в качестве левого операнда операции присваивания, но об этом в свое время.) Следующая операция простого присваивания $а = $Ь+3;

вычислит значение правого операнда и присвоит его переменной $а, т.е. сохранит в области памяти, выделенной для переменной $а. Возвращаемым значением этой операции будет адрес области памяти переменной $а (правильное lvalue), или говоря проще, имя скалярной переменной $а, которое снова можно использовать в качестве левого операнда операции присваивания. Таким образом, в языке Perl следующая операция присваивания

($а = $Ь) = 3;

является синтаксически правильной и в результате ее вычисления переменной $а будет присвоено значение з, так результатом вычисления операции присваивания $а = $ь будет присвоение переменной $а значения переменной $ь, а возвращаемым значением можно считать переменную $а, которой в следующей операции присваивается значение з. Читатель спросит: "А зачем городить такие сложности, если тот же самый результат можно получить простой операцией присваивания $а = з?". Действительно, замечание справедливое. Но на этом примере мы показали, как можно использовать операцию присваивания в качестве правильного lvalue. Более интересные примеры мы покажем, когда определим составные операции присваивания, заимствованные из языка С.

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

$varl = $var2 = $varl[0] =34;

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

$а = $а+3;

Однако, язык Perl предлагает более эффективный способ решения подобных проблем, предоставляя в распоряжение программиста бинарную операцию составного присваивания +=, которая прибавляет к значению левого операнда, представляющего правильное lvalue, значение правого операнда и результат присваивает переменной, представленной левым операндом. Таким образом, оператор составного присваивания

$а += 3; I Результат: $а = $а+3

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

Для всех бинарных операций языка Perl существуют соответствующие составные операции присваивания. Все они, вместе с примерами их использования, собраны в табл. 4.2.

Таблица 4.2. Составные операции присваивания

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

  Замечание
При использовании операции присваивания (простой или составной) в качестве левого операнда другой операции присваивания обязательно ее заключение в круглые скобки. Иначе может сгенерироваться синтаксическая ошибка, или выражение будет интерпретировано не так, как задумывалось. При наличии нескольких операций присваивания в одном выражении без скобок интерпретатор peri начинает его разбор справа. Например, если последнее выражение примера 4.11 записать без скобок
$а += 2 **= 2 -•= 1;

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

2 -= 1;

и сообщит об ошибке, так как ее синтаксис ошибочен (левый операнд не является переменной или элементом массива).
Ссылки и операция разыменования
При выполнении программы Perl она, вместе с используемыми ею данными, размещается в оперативной памяти компьютера. Обращение к данным осуществляется с помощью символических имен — переменных, что является одним из преимуществ использования языка высокого уровня типа Perl. Однако иногда необходимо получить непосредственно адрес памяти, где размещены данные, на которые мы ссылаемся в программе с помощью переменной. Для этого в языке определено понятие ссылки, или указателя, который содержит адрес переменной, т. е. адрес области памяти, на которую ссылается переменная. Для получения адреса переменной используется операция ссылка, знак которой "\" ставится перед именем переменной:
$m ='5;

$рт = \$m; f Ссылка на скалярную величину

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

@аrrау = (1,2,3);

$раггау = \@аггау; # Ссылка на массив скаляров

%hesh = (опе=>1, two=>2, three=>3);

$phesh = \%hesh; § Ссылка на массив скаляров

Если распечатать в программе переменные-ссылки $pm, $parray и $phesh, то мы увидим строки, подобные следующим:

SCALAR(Ox655a74) ARRAY (Ох655ЫО) HASH(0x653514)

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

Для получения содержимого области памяти, на которую ссылается переменная-указатель, требуется выполнить операцию разыменования ссылки. Для этого достаточно перед именем такой переменной поставить символ, соответствующий типу данных, на который ссылается переменная ($, @, %):

@keys = keys(%$phash); # Массив ключей хеша @values = values(%$phash); # Массив значений хеша print "$$pm \n@$parray \n@keys \n@values";

Этот фрагмент кода для определенных в нем переменных-ссылок на скаляр, массив и хеш напечатает их значения:

5 # Значение скалярной переменной $m

123 # Значения элементов массива скаляров @аrrау

three two one # Ключи хеша %hash

321 # Значения хеша %hash

Использование описанной выше простой операции разыменования может приводить к сложным, трудно читаемым синтаксическим конструкциям при попытке получить значения элементов сложных конструкций: массива массивов, массива хешей и т. п. Для подобных целей в языке Perl предусмотрена бинарная операция ->, левым операндом которой может быть ссылка на массив скаляров или хеш-массив, а правым операндом индекс элемента массива или хеша, значение которого необходимо получить: print "$parray->[0], .$parray->[1], .$parray->[2]\n"; print "$phash->{one} r $phash->{two}, $phash->{three}\n";

Эти операторы напечатают значения элементов массива ©array и хеша %hash.
 Операции связывания
Операции сопоставления с образцом, используемые многими утилитами обработки текста в Unix, являются мощным средством и в языке Perl. Эти операции с регулярными выражениями включают поиск (m//), подстановку (s///) и замену символов (tr///) в строке. По умолчанию они работают со строкой, содержащейся в системной переменной $_. Операции =~ и \ ~ связывают выполнение сопоставления с образцом над строкой, содержащейся в переменной, представленной левым операндом этих операций: $_ = "It's very interesting!";
s/very/not/; # Переменная $_ будет содержать строку

# "It's not interesting!"

$m = "my string";

$m =~ s/my/our/; i Переменная $m будет содержать строку

tt "our string"

Возвращаемым значением операции =~ является Истина, если при выполнении соответствующей ей операции сопоставления с образцом в строке была найдена последовательность символов, определяемая регулярным выражением, и Ложь в противном случае. Операция ! ~ является логическим дополнением к операции =~. Следующие два выражения полностью эквивалентны:

$m !~ m/my/our/; not $m =~ m/my/our/;

Именованные унарные операции
В языке Perl определено большое количество встроенных функций, выполняющих разнообразные действия. Некоторые из них, с точки зрения синтаксического анализатора языка, на самом деле являются унарными операциями, которые и называют именованными унарными операциями, чтобы отличить их от унарных операций со специальными символами в качестве знаков операций (например, унарный минус "-", операция ссылки "\", логического отрицания "!" и т. д.). Некоторые из именованных унарных операций перечислены ниже:
chdir, cos, defined, goto, log, rand, rmdir, sin, sqrt, do, eval, return (Является ли функция унарной операцией, можно определить в приложении 1.)

К именованным унарным операциям относятся также все операции проверки файлов, синтаксис которых имеет вид:

-символ [имя_файла\дескриптор_файла]

Например, для проверки существования файла определена операция -е, выяснить возможность записи в файл можно операцией -w.

Операции ввода/вывода
Для взаимодействия и общения с внешним окружением в любом языке программирования предусмотрены операции ввода/вывода. Perl не является исключением. В нем определен ряд операций, обеспечивающих ввод и вывод данных в/из программы.  
Операция print
С этой операцией вывода мы уже немного знакомы. Операция print — унарная операция, правым операндом которой служит задаваемый список значений, которые она отображает по умолчанию на экране монитора. Операцию, операндом которой является список, называют списковой операцией. Внешне ее можно задать как вызов функции, заключив ее операнд в круглые скобки. Следующие операции эквивалентны:
print "@m", "\n", $m, "\n"; print("@m", "\n", $m, "\n");

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика