Логические выражения
Существуют задачи, при решении которых появляются величины, принимающие только одно из двух возможных значений. Одно из этих состояний принимается за «истинное», а другое за «ложное». Для этих величин не может быть задано никакое третье значение (естественно, процесс переключения такой величины из одного состояния в другое не рассматривается), например, лампочка может быть включена или выключена. Обычно логические величины появляются при проверке логических отношений.
Логические величины входят в состав логических выражений, используемых в операторах управления программой (операторах условного перехода, операторах цикла и т.д.). Логические выражения состоят из арифметических выражений, логических отношений и логических операций.
В языке C# определены следующие операции логических отношений:
> строго больше;
< строго меньше;
>= больше или равно;
<= меньше или равно;
!= не равно;
== сравнение на равенство;
Перечисленные знаки логических отношений часто соединяют арифметические выражения. Приоритет арифметических операций выше операций сравнения. Поэтому при проверке логического отношения, сначала выполняется вычисление арифметических выражений (чтобы с обеих сторон от знака логического отношения были получены конкретные числа), а после этого выполняется сравнение. Ниже приведены примеры записи логических отношений:
x < 0.5
a + 1 >= b/2 - 1
c != S
В результате проверки логических отношений формируются значения истинности и ложности.
Помимо числовых величин в логических отношениях могут участвовать символы и строки. В этом случае символы сравниваются по своим числовым кодам в соответствие с кодовой таблицей. Аналогично строки сравнивают по кодам символов слева направо до первого, не совпадающего по коду символа, который и определяет, какая из строк больше (или меньше).
В языке C# существует тип данных bool, позволяющий объявлять переменные логического типа, которые могут принимать значения true (истинно) и false (ложно).
Кроме операций логических отношений в логических выражениях могут использоваться логические операции. Определены следующие логические операции:
Логическая операция Название Обозначение
Отрицание NOT (Не) !
Логическое сложение OR (ИЛИ) ||
Логическое умножение AND (И) &&
Исключительное ИЛИ (двуместная операция) XOR ^
Исключительное ИЛИ (одноместная операция) XOR ~
Поразрядное Логическое сложение OR (ИЛИ) |
Поразрядное Логическое умножение AND (И) &
Результаты выполнения логических операций наглядно можно представить в виде таблиц истинности. В этих таблицах A и B операнды, а R - результат выполнения операции. Следует отметить, что название логических операций соответствует их смыслу в разговорном языке (как русском, так и английском).
В языке С++ нет жесткого выделения логических констант, все целые числа кроме нуля в логических выражениях соответствуют понятию true, а целочисленный нуль соответствует понятию false. В языке C# эти значения принимают только переменные типа bool. Однако для наглядности пояснения логических операций удобно использовать систему языка С++, считая что 1 соответствует понятию true, 0 соответствует false.
|| (OR)
&& (AND) ^ (XOR)
A B R A B R A B R
0 0 0 0 0 0 0 0 0
0 1 1 0 1 0 0 1 1
1 0 1 1 0 0 1 0 1
1 1 1 1 1 1 1 1 0
Как видно из таблицы для операции ИЛИ (||), результат получается истинным, если истинным является хотя бы один из операндов. Логическое сложение отличается от арифметического тем, что при сложении двух единиц (значений «истинно») результат равен 1, а не 2. Это и не удивительно, поскольку для логических величин нет третьего состояния.
Обычно логические операции позволяют создать фильтры для отбора данных по какому-либо критерию. Логическая операция ИЛИ позволяет выбрать один или несколько элементов из списка. Например, если выполняется набор группы студентов специальности АСУ, желающих поехать в туристическую поездку, то подходящими кандидатами являются ИЛИ студенты группы 2бАСУ1, ИЛИ студенты группы 2бАСУ2. Таким образом, в группу могут попасть как студенты любой из групп, так и из обеих групп вместе.
Операция логического умножения И (&&) выдает результат «истинно», если истинными являются все участвующие в операции операнды. Эта операция практически не отличается от арифметического умножения, и позволяет выбрать элементы с полным совпадением ключевых признаков. Например, для проверки попадания величины в заданный диапазон значений требуется, чтобы значение величины было больше минимального значения И меньше минимального значения.
Операция исключительного ИЛИ (^ либо ~) выдает результат «истинно», если истинным является только один участвующий в операции операнд. Эта операция в разговорном языке соответствует конструкции ИЛИ – ИЛИ («или вы ликвидируете задолженность, или будете отчислены из института»). При построении фильтров эта операция обеспечивает выбор альтернативы. Эта операция существует в двух вариантах: для двухместных операций (^) и для поразрядных операций (~).
Безусловно, также как и в арифметических выражениях, в логическом выражении могут быть более двух операндов для любой из логических операций, а последние могут быть связаны между собой в любых сочетаниях.
Перечисленные выше логические операции могут выполняться для результатов проверки логических отношений, но они могут также использоваться для поразрядного выполнения, т.е. для выполнения логических операций над отдельными разрядами двоичного представления элемента данных. Поразрядные логические операции позволяют выполнить три операции:
• Установить в единицу отдельный бит в двоичном представлении числа.
• Проверить значение отдельного бита в двоичном представлении числа
• Сбросить в нуль значение отдельного бита в двоичном представлении числа.
Для операции поразрядного логического умножения записывают один символ «&». Пусть объявлены и инициализированы две переменные a и mask, как показано ниже. В примечаниях приведены двоичные коды инициализированных переменных a, mask и результата c. Числа представлены в шестнадцатеричных кодах для наглядности, в компьютере числа всегда записаны в двоичной системе счисления.
Ниже представлена подпрограмма, распечатывающая двоичный код числа.
// Подпрограмма представления числа в двоичном коде
// n - число, w - сколько младших цифр представить
static string conv(uint n, int w)
{
uint mask = 1;
char p;
string st = ""; // Пустая строка для двоичных цифр
for (int i = 0; i < w; ++i)
{
if (((n & mask) != 0) == true) p = 1;
else p = 0;
st = p.ToString() + st; // Сборка строки двоичного кода
mask <<= 1; // Сдвиг маски на 1 двоичный разряд влево
}
return st;
}
Операция поразрядного умножения & выполняется отдельно с каждой парой соответствующих друг другу двоичных разрядов
int a, mask, c;
a = 0xDC; // Двоичный код 11011100
mask = 0x17; // Двоичный код 00010111
c = a & mask; // Двоичный код 00010100 → 0x14
Console.WriteLine(" a = 11011100
mask = 00010111
c = 00010100"+
"
В шестнадцатеричной системе
"+
"Результат операции "a & mask" = {0:X}", c);
Console.ReadKey();
После выполнения этой операции будет выведено:
В результате выполнения операции единицы появляются там, где были единицы в соответствующих друг другу двоичных разрядах операндов. Таким образом, если одно из чисел рассматривать как маску (в примере это переменная mask), то с помощью поразрядной операции & можно передать в результат двоичные разряды, находящиеся «под маской».
С помощью приведенной ниже программы можно подсчитать количество единиц в двоичном представлении числа.
int count = 0;
mask = 0x0001; // Маска
for (int i = 0; i < 17; ++i)
{
c = a & mask;
if (c != 0) count++;// Если 1 в маске и в проверяемом разряде, счетчик++
mask <<= 1; // Сдвинуть 1 в маске влево на один двоичный разряд
}
Console.WriteLine("В числе a = 11011100 {0} единиц ", count);
Результат выполнения программы:
В двоичном представлении числа четные числа в самом младшем разряде всегда имеют значение нуль. Поэтому для проверки четности числа вместо вычисления остатка от деления на 2 можно записать проверку на наличие единицы в двоичном коде числа:
if ((x & 1) == 1)
где x целое число (число 1 в двоичном представлении – это единица в самом младшем разряде). Если результат проверки истинный – число нечетное, иначе – четное.
Для поразрядного выполнения операции логического сложения записывают только один символ «|». Проинициализируем, как показано ниже переменные a и b.
int a, b, c;
a = 0xC0; // Двоичный код 11000000
b = 0x10; // Двоичный код 00010000
c = a | b; // Двоичный код 11010000 → 0xD0
Console.WriteLine("Поразрядное a | b = {0:X}", c);
После выполнения этой операции будет выведено:
Из приведенного примера видно, что поразрядная операция логического сложения позволяет записывать в двоичное представление числа двоичные единицы в заданные позиции.
Операция «Исключительного ИЛИ» XOR может быть двухместной (бинарной), тогда она выполняется поразрядно для каждой из соответствующих друг другу двоичных разрядов операндов в паре (операция обозначается символом ^).
В некоторых задачах возникает потребность иметь переменную, которая при каждом обращении к ней изменяет свое состояние: если она имела состояние «истинно», то должна получить состояние «ложно». Примером такой задачи является переключение режима ввода информации, например, при работе в редакторе Word, с режима «Вставки» на режим «Замены» и обратно. Эту операцию можно реализовать с помощью поразрядной операции Исключительного ИЛИ (XOR). Фрагмент программы имеет:
bool t = true;
<Начало цикла>
{
if (t == true) // Действие при первом проходе
else //Действие при втором проходе
<Действия внутри цикла>
t ^= false; // Это сокращенная форма записи оператора t = t ^ false;
}
<Конец цикла>
Для установки в нуль отдельного бита, сохраняя единицы в остальных разрядах, требуется создать маску, которая содержит нулевой бит в изменяемом разряде и единицы во всех остальных разрядах. Для этого можно задать маску как обычно для поразрядной операции ИЛИ, а затем применить к ней одноместную операцию XOR.
static void Main(string[] args)
{
uint a, mask, c;
mask = 0x08; // Маска
a = 0xDC; // Исходное число
// Поразрядная операция И с инвертированной маской
c = a & ~mask;
Console.WriteLine(" Операция a & ~ mask результат
{0,8:X}", c);
Console.WriteLine(" {0} исходное число
{1} маска", conv(a,8),conv(mask,8));
Console.WriteLine("{0}",conv(c,8));
Console.ReadKey();
}
После выполнения этой операции будет выведено:
Кроме перечисленных возможно также выполнение операций сдвига содержимого для целочисленных переменных. Для обозначения этих операций используются знаки >>n (сдвиг вправо) или <<n (сдвиг влево), где n указывает: на сколько разрядов (двоичных) следует выполнить сдвиг. Например:
char t, s;
int x, y;
. . .
t = s >> 4;
x = y В этом примере переменной t присваивается значение переменной s после сдвига значения последней на 4 двоичных разряда вправо, а переменной x сдвинутое на один разряд влево содержимое переменной y.
Операция сдвига влево на каждый разряд сдвига увеличивает сдвигаемое значение в 2 раза (умножает на 2) и заполняет освобождающиеся справа разряды числа нулями. Сдвиг вправо равносилен делению числа на два, но при этом положительные числа дополняются слева нулями, а отрицательные единицами. Это может привести к ошибке, поскольку при сдвиге вправо отрицательного числа на количество разрядов, равное разрядности числа, результат всегда будет состоять из одних двоичных единиц, независимо от начального значения числа. Если же переменная объявлена с модификатором unsigned, то при сдвиге вправо число слева дополняется нулями, то есть, искажение результата не происходит
Логические выражения в C#
Лекции по предмету «Программирование»