Выбрать главу

      u = x>>2; v = y<<2; w = x/4;

      Console.WriteLine("x= " + x + y= " + у + u=x>>2 = "+u

          + v=y<<2 " + v + w = x/4 = " + w);

}//Shift

Логические операции

Начну с предупреждения тем, кто привык к языку C++. Правила работы с логическими выражениями в языках C# и C++ имеют принципиальные различия. В языке C++ практически для всех типов существует неявное преобразование в логический тип. Правило преобразования простое, — ненулевые значения трактуются как истина, нулевое — как ложь. В языке C# неявных преобразований к логическому типу нет даже для целых арифметических типов. Поэтому вполне корректная в языке C++ запись:

int k1 = 7;

if (k1) Console.WriteLine("ok!");

незаконна в программах на С#. На этапе трансляции возникнет ошибка, поскольку вычисляемое условие имеет тип int, а неявное преобразование этого типа к типу bool отсутствует.

В языке C# более строгие правила действуют и для логических операций. Так, запись

if(k1 && (х>у)),

корректная в языке C++, приводит к ошибке в программах на С#, поскольку операция && определена только для операндов типа bool, а в данном выражении один из операндов имеет тип int. в языке C# в данных ситуациях следует использовать записи:

if(k1>0)

if((k1>0) && (x>y))

После этого важного предупреждения перейду к более систематическому изложению некоторых особенностей выполнения логических операций. Так же, как и в языке C++, логические операции делятся на две категории: одни выполняются над логическими значениями операндов, другие осуществляют выполнение логической операции над битами операндов. По этой причине в C# существуют две унарные операции отрицания — логическое отрицание, заданное операцией"!", и побитовое отрицание, заданное операцией "~". Первая из них определена над операндом типа bool, вторая — над операндом целочисленного типа, начиная с типа int и выше (int, uint, long, ulong). Результатом операции во втором случае является операнд, в котором каждый бит заменен его дополнением. Приведу пример:

/// <summary>

/// Логические выражения

/// </summary>

public void Logic()

{

     //операции отрицания ~,!

     bool b1,b2;

     b1= 2 *2==4; b2 =!b1;

     //Ь2= ~1;

     uint j1 = 7, j2;

     j2= ~j1;

     //j2 =!j1;

     int j4 = 7, j5;

     j5 = ~j4;

     Console.WriteLine("uint j2 = " + j2 +" int j5 = " + j5);

}//Logic

В этом фрагменте закомментированы операторы, приводящие к ошибкам. В первом случае была сделана попытка применения операции побитового отрицания к выражению типа bool, во втором — логическое отрицание применялось к целочисленным данным. И то, и другое в C# незаконно. Обратите внимание на разную интерпретацию побитового отрицания для беззнаковых и знаковых целочисленных типов. Для переменных j5 и j2 строка битов, задающая значение — одна и та же, но интерпретируется по-разному. Соответствующий вывод таков:

uint j2 = 4294967288 int j5 = -8

Бинарные логические операции "&& — условное И" и "II — условное ИЛИ" определены только над данными типа bool. Операции называются условными или краткими, поскольку, будет ли вычисляться второй операнд, зависит от уже вычисленного значения первого операнда. В операции если первый операнд равен значению false, то второй операнд не вычисляется и результат операции равен false. Аналогично, в операции "II", если первый операнд равен значению true, то второй операнд не вычисляется и результат операции равен true. Ценность условных логических операций заключается не в их эффективности по времени выполнения. Часто они позволяют вычислить логическое выражение, имеющее смысл, но в котором второй операнд не определен. Приведу в качестве примера классическую задачу поиска по образцу в массиве, когда разыскивается элемент с заданным значением (образец). Такой элемент в массиве может быть, а может и не быть. Вот типичное решение этой задачи в виде упрощенном, но передающем суть дела:

//Условное And — &&

int[] ar= {1,2,3};

int search = 7; int i=0;

while ((i < ar.Length) && (ar[i]!= search)) i++;

if(i<ar.Length) Console.WriteLine("Образец найден");

else Console.WriteLine("Образец не найден");

Если значение переменной search (образца) не совпадает ни с одним из значений элементов массива аr, то последняя проверка условия цикла while будет выполняться при значении i, равном ar.Length.