Теги: Си логические операторы, логическое отрицание, логическое НЕ, !, логическое ИЛИ, логическое сложение, OR, логическое умножение, логическое И, AND, порядок выполнения логических операторов
Л огические операторы – это операторы, которые принимают в качестве аргументов логические значений (ложь или истину) и возвращают логическое значение. Как и обычные операторы, они могут быть одноместными (унарными, т.е. принимать один аргумент), двуместными (бинарные, принимают два аргумента), трёхместными и т.д.
Особенностью языка си является то, что в нём нет типа, хранящего булево значение (ложь или истину). В си ложью (логическим нулём) считается целочисленный 0, а любое ненулевое целое будет логической истиной. Например
#include
Логические значения обычно порождаются операторами сравнения (==, !=, >, <, >=. <=).
В языке си представлено три логических оператора: И, ИЛИ и НЕ. Начнём с самого простого
О ператор НЕ (NOT) используется для того, чтобы инвертировать значение аргумента. Т.е., если ему передали истину, то он вернёт ложь, если получил ложь в качестве аргумента, то вернёт истину.
X | NOT X |
---|---|
0 | 1 |
1 | 0 |
В си отрицание представлено оператором!. Например
#include
Как и в обычной логике, здесь действует закон двойного отрицания – отрицание отрицания можно опустить.
О ператор И (AND, логическое умножение) возвращает истину тогда и только тогда, когда оба аргумента являются истиной.
X | Y | X AND Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
В си логическое умножение представлено оператором &&. Например, задача – в кружок военных спейсмаринов допускаются только совершеннолетние граждане мужского пола. То есть, претендентом может стать только тот, для которого одновременно два условия являются истиной
Оператор И может применяться последовательно к нескольким аргументам. Для него действует ассоциативный и коммутативный законы. Усовершенствуем программу, будем также вводить рост:
#define _CRT_SECURE_NO_WARNINGS
#include
Также условие могло быть записано
(gender == "M" && age > 17) && height >= 180
Gender == "M" && (age > 17 && height >= 180)
(age > 17 && height >= 180) && gender == "M"
О ператор логическое ИЛИ (логическое сложение, OR) истинен тогда, когда истиной является хотя бы один его аргумент.
X | Y | X OR Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
В си ИЛИ представлен оператором ||. Например, усовершенствуем программу: теперь пол можно вводить как большой, так и маленькой буквой
#define _CRT_SECURE_NO_WARNINGS
#include
Как и в случае оператора И, ИЛИ коммутативен и ассоциативен.
Операторы можно перемешивать друг с другом, создавая сложные операторы
#define _CRT_SECURE_NO_WARNINGS
#include
Стоит только помнить о том, что оператор отрицания имеет больший приоритет, чем И или ИЛИ, поэтому будет выполняться в первую очередь. Если может случиться ситуация, когда порядок выполнения не ясен, определите его с помощью скобок.
Пример: закон де-Моргана. Чтобы сменить И на ИЛИ (или наоборот), необходимо инвертировать значения всех операндов, заменить И на ИЛИ (или ИЛИ на И) и инвертировать конечный результат. В случае с нашим условием
(age > 17 && height >= 180) && (gender == "M" || gender == "m")
Рассмотрим сначала кусок
(age > 17 && height >= 180)
Меняем все значения на обратные
(!(age > 17) && !(height >= 180))
заменяем оператор && на ||
(!(age > 17) || !(height >= 180))
и инвертируем ответ
!(!(age > 17) || !(height >= 180))
Как видим, результат тот же. Очевидно, что
!(age > 17)
эквивалентно
Age <= 17
Таким образом, изменим условие
!(age <= 17 || height < 180)
Поменяем таким же образом вторую скобку
(gender == "M" || gender == "m")
!(gender != "M" && gender != "m")
!(age <= 17 || height < 180) && !(gender != "M" && gender != "m")
Теперь можно применить это же правило и для всего выражения
!((age <= 17 || height < 180) || (gender != "M" && gender != "m"))
Р ассмотрим выражение
A && b && c && d
где a, b, c, d – логические значения. Всё выражение равно истине тогда и только тогда, когда все операнды истинны. Если хотя бы один из операндов ложь, то остальные уже не важны. Поэтому, для оптимизации работы, вычисление происходит слева направо и останавливается, как только был найден первый операнд, равный нулю.
В си оператор присваивания может возвращать значение. Иногда он используется непосредственно в условии:
#define _CRT_SECURE_NO_WARNINGS
#include
В данном случае, оператор malloc не будет выполнен, так как первый операнд a равен 0 (соответственно, всё выражение равно нулю). Таким образом, оператор free попытается очистить память, которую не может очистить (т.к. p продолжит ссылаться на a). Если же мы поменяем a = 1, то всё отработает без проблем.
То же самое происходит и при выполнение ||. Выражение
A || b || c || d
выполняется слева направо до тех пор, пока не встретит первое ненулевое значение. После этого выполнение останавливается, так как известно, что всё выражение равно истине.
Синтаксис оператора присвоения языка СИ имеет вид:К математическим операциям для вещественных и целочисленных вычислений языка СИ относят обычные арифметические операции:
сложения (+),
вычитания (-),
умножения (*),
деления (/).
Соответствие типа результата от типов операндов
Вот таблица истинности для этих операций:
первый операнд | второй операнд | операция | ||
и | или | исключающее или | ||
0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
Побитовые операции
Унарной побитовой операцией является операция отрицания, обозначаемая символом тильды (~).
Пример:
unsigned char a = 10, b; //a: 00001010 = 10
b = ~a; //b: 11110101 = 245
Операции сдвига
Операции сдвига осуществляют побитовый сдвиг целого значения, указанного в первом операнде, вправо (символ >>) или влево (символ
<<) на указанное во втором операнде целое число бит. Пример:
unsigned char a = 10, b, c; //a: 00001010 = 10
b = a << 2; //b: 00101000 = 40
c = a >> 1; //c: 00000101 = 5
Операции инкремента и декремента
Операции инкремента (знак ++) и декремента (знак --) являются унарными и осуществляют увеличение и уменьшение целого значения на
единицу соответственно.
int a = 10, b, c;
b = ++a //пред- инкремент b == 11
c = a++; //пост- инкремент с == 11
Операции отношения (сравнения)
В языках программирования операции отношения (сравнения) являются бинарными операциями, осуществляющими сравнение двух операндов и
возвращающие результат сравнения в виде логического значения. В языке СИ принято логические значения ИСТИНА и ЛОЖЬ интерпретировать
посредством целочисленных значений:
0 – ЛОЖЬ, 1 – ИСТИНА.
Обозначение Название
>
Больше
<
Меньше
>=
Больше или равно
<=
Меньше или равно
==
Равно
!=
Не равно
Примеры
Несколько примеров использования операций сравнения:
int a=5, b=4, c=10, x, y;
x = a > b; //x == 1
y = c == a; //y == 0
Логические операции в СИ
Логические операции – унарные или бинарные операции, осуществляющие действия над логическими значениями и возвращающие логическое значение. Набор логических операций у разных языков программирования может быть различен.
Логические операции
Приоритеты операций
++, -- | Операции пост- инкремента и декремента |
() | Вызов функции, группировка операций |
Обращение к элементу массива | |
-> | Обращение к полю структуры или объединения через указатель |
. | Обращение к полю структуры или объединения |
++, -- | Операции пред-инкремента и декремента |
! | Логическое «НЕ» |
~ | Бинарное отрицание(инверсия) |
+, - | Унарные плюс и минус |
& | Операция взятия адреса |
* | Разыменование указателя |
sizeof | Оператор определения размера |
(type) | Оператор преобразования типа |
* | Умножение |
/ | Деление |
% | Взятие остатка от деления |
+ | Сложение |
- | Вычитание |
<<, >> | Побитовые сдвиги влево и вправо |
<, <=, >, >= | Операции сравнения |
==, != | Операции сравнения |
& | Побитовое «И» |
^ | Побитовое «Исключающее ИЛИ» |
| | Побитовое «ИЛИ» |
Логическое «И» | |
|| | Логическое «ИЛИ» |
?: | Условная операция |
= | Оператор простого присвоения |
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=,|= | Усовершенствованные операторы присвоения |
, | Запятая |
Особенности трансляторов
Схема автоматического приведения типа
Оператор приведения типа
int a = 15, b = 2; double r = 0.0;Условная операция
{
double x,y;
scanf("%lf %lf”,&x,&y);
double max = (x > y) ? x: y;
return 0;
}
Int main(int argc, char *argv)
{
double x, y, z;
printf("Введите значения: ");
scanf("%lf %lf %lf",&x,&y,&z);
double max = (x > y) ? ((x > z) ? x: z): ((y > z) ? y:z);
printf("Максимальное значение: %lf\n",max);
return 0;
}
Int main(int argc, char *argv)
{
double a;
printf("Введите значение: ");
scanf("%lf",&a);
a *= (a *=a);
printf("Результат: %lf\n",a);
return 0;
}
Int main(int argc, char *argv)
{
double a,b,c;
printf("Введите коэффициенты A, B и С: ");
scanf("%lf %lf %lf",&a,&b,&c);
double d = b*b-4*a*c;
int n = (d < 0.0)?0:(d > 0.0)?2:1;
printf("Количество корней: %d\n",n);
return 0;
}
Так как в предыдущей статье, я впервые использовал логическую операцию, расскажу, какие они бывают, сколько их и как ими пользоваться.
Логические операции образуют сложное (составное) условие из нескольких простых (два или более) условий. Эти операции упрощают структуру программного кода в несколько раз. Да, можно обойтись и без них, но тогда количество ифов увеличивается в несколько раз, в зависимости от условия. В следующей таблице кратко охарактеризованы все логические операции в языке программирования С++, для построения логических условий.
Сейчас следует понять разницу между логической операцией И и логической операцией ИЛИ , чтобы в дальнейшем не путаться. Пришло время познакомиться с типом данных bool –логический . Данный тип данных может принимать два значения: true (истина) и false (ложь). Проверяемое условие в операторах выбора имеет тип данных bool . Рассмотрим принцип работы следующей программы, и все будет понятно со всеми этими логическими операциями.
// or_and_not.cpp: определяет точку входа для консольного приложения.
#include "stdafx.h"
#include
Строки 9 и 10 вам должны быть понятны, так как здесь инициализируются переменные типа bool . Причем каждой переменной присваивается значение true или false . Начиная с 9-й строки и заканчивая 20-й , показано использование логических операций. Результат работы программы (см. Рисунок 1).
Tablica istinnosti log operacii && true && false: 0 false && true: 0 true && true: 1 false && false: 0 Tablica istinnosti log operacii || true || false: 1 false || true: 1 true || true: 1 false || false: 0 Tablica istinnosti log operacii ! !true: 0 !false: 1 Для продолжения нажмите любую клавишу. . .
Рисунок 1 — Логические операции С++
Наверное, у вас возникает вопрос, «А что это за нолики и единички?». Если есть вопрос, то на него нужно ответить. Отвечаю: «Нолик-это представление логического значения false (ложь), ну а единички – это логическое true (истина)». Коротко поясню некоторые моменты. Составное условие с использованием логического И истинно только в том случае, когда истинны оба простых условия. Во всех остальных случаях составное условие ложно. Составное условие с использованием логического ИЛИ ложно только в том случае, когда ложные оба простых условия. Во всех остальных случаях составное условие истинно. Логическое отрицание НЕ является унарной операцией, и она не комбинирует два условия, в отличие от логических операций И и ИЛИ , которые являются бинарными операциями. Логическое отрицание позволяет перевернуть смысл условия, что в некоторых случаях очень удобно. Условие с логическим отрицанием истинно в том случае, если это же условие ложно без отрицания, и наоборот.
Последнее обновление: 19.06.2017
Отдельный набор операций представляет условные выражения. Такие операции возвращают логическое значение, то есть значение типа bool : true , если выражение истинно, и false , если выражение ложно. К подобным операциям относятся операции сравнения и логические операции.
В операциях сравнения сравниваются два операнда и возвращается значение типа bool - true , если выражение верно, и false , если выражение неверно.
Сравнивает два операнда на равенство. Если они равны, то операция возвращает true , если не равны, то возвращается false :
B; // false
Сравнивает два операнда и возвращает true, если операнды не равны, и false, если они равны.
Int a = 10; int b = 4; bool c = a != b; // true bool d = a!=10; // false
Операция "меньше чем". Возвращает true, если первый операнд меньше второго, и false, если первый операнд больше второго:
Int a = 10; int b = 4; bool c = a < b; // false
Операция "больше чем". Сравнивает два операнда и возвращает true, если первый операнд больше второго, иначе возвращает false:
Int a = 10; int b = 4; bool c = a > b; // true bool d = a > 25; // false
Операция "меньше или равно". Сравнивает два операнда и возвращает true, если первый операнд меньше или равен второму. Иначе возвращает false.
Int a = 10; int b = 4; bool c = a <= b; // false bool d = a <= 25; // true
Операция "больше или равно". Сравнивает два операнда и возвращает true, если первый операнд больше или равен второму, иначе возвращается false:
Int a = 10; int b = 4; bool c = a >= b; // true bool d = a >= 25; // false
Операции <, > <=, >= имеют больший приоритет, чем == и!=.
Также в C# определены логические операторы, которые также возвращают значение типа bool . В качестве операндов они принимают значения типа bool . Как правило, применяются к отношениям и объединяют несколько операций сравнения.
Операция логического сложения или логическое ИЛИ. Возвращает true, если хотя бы один из операндов возвращает true.
Bool x1 = (5 > 6) | (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x2 = (5 > 6) | (4 > 6); // 5 > 6 - false, 4 >
Операция логического умножения или логическое И. Возвращает true, если оба операнда одновременно равны true.
Bool x1 = (5 > 6) & (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается false bool x2 = (5 < 6) & (4 < 6); // 5 < 6 - true, 4 < 6 - true, поэтому возвращается true
Операция логического сложения. Возвращает true, если хотя бы один из операндов возвращает true.
Bool x1 = (5 > 6) || (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x2 = (5 > 6) || (4 > 6); // 5 > 6 - false, 4 > 6 - false, поэтому возвращается false
Операция логического умножения. Возвращает true, если оба операнда одновременно равны true.
Bool x1 = (5 > 6) && (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается false bool x2 = (5 < 6) && (4 < 6); // 5 < 6 - true, 4 < 6 - true, поэтому возвращается true
Операция логического отрицания. Производится над одним операндом и возвращает true, если операнд равен false. Если операнд равен true, то операция возвращает false:
Bool a = true; bool b = !a; // false
Операция исключающего ИЛИ. Возвращает true, если либо первый, либо второй операнд (но не одновременно) равны true, иначе возвращает false
Bool x5 = (5 > 6) ^ (4 < 6); // 5 > 6 - false, 4 < 6 - true, поэтому возвращается true bool x6 = (50 > 6) ^ (4 / 2 < 3); // 50 > 6 - true, 4/2 < 3 - true, поэтому возвращается false
Здесь у нас две пары операций | и || (а также & и &&) выполняют похожие действия, однако же они не равнозначны.
В выражении z=x|y; будут вычисляться оба значения - x и y.
В выражении же z=x||y; сначала будет вычисляться значение x, и если оно равно true , то вычисление значения y уже смысла не имеет, так как у нас в любом случае уже z будет равно true . Значение y будет вычисляться только в том случае, если x равно false
То же самое касается пары операций &/&& . В выражении z=x&y; будут вычисляться оба значения - x и y.
В выражении же z=x&&y; сначала будет вычисляться значение x, и если оно равно false , то вычисление значения y уже смысла не имеет, так как у нас в любом случае уже z будет равно false . Значение y будет вычисляться только в том случае, если x равно true
Поэтому операции || и && более удобны в вычислениях, так как позволяют сократить время на вычисление значения выражения, и тем самым повышают производительность. А операции | и & больше подходят для выполнения поразрядных операций над числами.
Примечание. Все операции в результате дают значение типа bool
Операции сравнения и логические операции в результате дают значение типа bool, то есть true или false. Если же такое выражение встречается в контексте, требующем целого значения, true преобразуется в 1, а false – в 0. Вот фрагмент кода, подсчитывающего количество элементов вектора, меньших некоторого заданного значения:
Vector
Мы просто прибавляем результат операции “меньше” к счетчику. (Пара += обозначает
составной оператор присваивания, который складывает операнд, стоящий слева,
и операнд, стоящий справа. То же самое можно записать более компактно: elem_count
= elem_count + n. Мы рассмотрим такие операторы в разделе 4.4.)
Логическое И (&&) возвращает истину только тогда, когда истинны оба
операнда. Логическое ИЛИ (||) дает истину, если истинен хотя бы один из операндов.
Гарантируется, что операнды вычисляются слева направо и вычисление заканчивается,
как только результирующее значение становится известно. Что это значит? Пусть
даны два выражения:
Expr1 && expr2 expr1 || expr2
Если в первом из них expr1 равно false, значение всего выражения тоже будет
равным false вне зависимости от значения expr2, которое даже не будет вычисляться.
Во втором выражении expr2 не оценивается, если expr1 равно true, поскольку значение
всего выражения равно true вне зависимости от expr2.
Подобный способ вычисления дает возможность удобной проверки нескольких выражений
в одном операторе AND:
While (ptr != О && ptr->va1ue < upperBound && ptr->va1ue >= 0 && notFound(ia[ ptr->va1ue ])) { ... }
Указатель с нулевым значением не указывает ни на какой объект, поэтому применение
к нулевому указателю операции доступа к члену вызвало бы ошибку (ptr->value).
Однако, если ptr равен 0, проверка на первом шаге прекращает дальнейшее вычисление
подвыражений. Аналогично на втором и третьем шагах проверяется попадание величины
ptr->value в нужный диапазон, и операция взятия индекса не применяется к
массиву ia, если этот индекс неправилен.
Операция логического НЕ дает true, если ее единственный оператор равен false,
и наоборот. Например:
Bool found = false; // пока элемент не найден // и ptr указывает на объект (не 0) while (! found && ptr) { found = 1ookup(*ptr); ++ptr; }
Подвыражение
Дает true, если переменная found равна false. Это более компактная запись для
Found == false
Аналогично
Эквивалентно более длинной записи
If (found == true)
Использование операций сравнения достаточно очевидно. Нужно только иметь в виду, что, в отличие от И и ИЛИ, порядок вычисления операндов таких выражений не определен. Вот пример, где возможна подобная ошибка:
// Внимание! Порядок вычислений не определен! if (ia[ index++ ] < ia[ index ]) // поменять местами элементы
Программист предполагал, что левый операнд оценивается первым и сравниваться будут элементы ia и ia. Однако компилятор не гарантирует вычислений слева направо, и в таком случае элемент ia может быть сравнен сам с собой. Гораздо лучше написать более понятный и машинно-независимый код:
If (ia[ index ] < ia[ index+1 ]) // поменять местами элементы ++index;
Еще один пример возможной ошибки. Мы хотели убедиться, что все три величины ival, jval и kval различаются. Где мы промахнулись?
// Внимание! это не сравнение 3 переменных друг с другом if (ival != jva1 != kva1) // do something ...
Значения 0, 1 и 0 дают в результате вычисления такого выражения true. Почему?
Сначала проверяется ival != jval, а потом итог этой проверки (true/false – преобразованной
к 1/0) сравнивается с kval. Мы должны были явно написать:
if (ival != jva1 && ival != kva1 && jva1 != kva1)
// сделать что-то...
Найдите неправильные или непереносимые выражения, поясните. Как их можно изменить?
(Заметим, что типы объектов не играют роли в данных примерах.)
(a) ptr->iva1 != 0
(с) ptr != 0 && *ptr++
(e) vec[ iva1++ ] <= vec[ ival ];
(b) ival != jva1 < kva1 (d) iva1++ && ival
Язык С++ не диктует порядок вычисления операций сравнения для того, чтобы позволить компилятору делать это оптимальным образом. Как вы думаете, стоило бы в данном случае пожертвовать эффективностью, чтобы избежать ошибок, связанных с предположением о вычислении выражения слева направо?