Интернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»
Шрифт:
Интервал:
Закладка:
else Console.WriteLine("q!=n");
double x=7, у =3, u,v,w;
u = x/y; v= u*y;
w= x%y;
if (v==x) Console.WriteLine("v=x");
else Console.WriteLine("v!=x");
decimal d1=7, d2 =3, d3,d4,d5;
d3 = d1/d2; d4= d3*d2;
d5= d1%d2;
if (d4==d1) Console.WriteLine("d4=d1");
else Console.WriteLine("d4!=d1");
}//Ariphmetica
При проведении вычислений в двух первых случаях проверяемое условие оказалось истинным, в третьем — ложным. Для целых типов можно исходить из того, что равенство n = n/m*m + n%m истинно. Для типов с плавающей точкой выполнение точного равенства х = х/у*у следует считать скорее случайным, а не закономерным событием. Законно невыполнение этого равенства, как это имеет место при вычислениях с фиксированной точкой.
Операции отношения
Операции отношения можно просто перечислить — в объяснениях они не нуждаются. Всего операций 6 (==, =, <, >, <=, >=). Для тех, кто не привык работать с языком C++, стоит обратить внимание на запись операций "равно" и "не равно".
Операции проверки типов
Операции проверки типов is и as будут рассмотрены в последующих лекциях, (см. лекцию 19).
Операции сдвига
Операции сдвига вправо "<<" и сдвига влево "<<" в обычных вычислениях применяются редко. Они особенно полезны, если данные рассматриваются как строка битов. Результатом операции является сдвиг строки битов влево или вправо на к разрядов. В применении к обычным целым положительным числам сдвиг вправо равносилен делению нацело на 2К, а сдвиг влево — умножению на 2К. Для отрицательных чисел сдвиг влево и деление дают разные результаты, отличающиеся на единицу. В языке C# операции сдвига определены только для некоторых целочисленных типов — int, uint, long, ulong. Величина сдвига должна иметь тип int. Вот пример применения этих операций:
/// <summary>
/// операции сдвига
/// </summary> public void Shift()
{
int n = 17,m =3, p,q;
p= n>>2; q = m<<2;
Console.WriteLine("n= " + n + m= " + m + p=n>>2 = "+p
+ q=m<<2 " + q);
long x=-75, у =-333, u,v,w;
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("Образец не найден");