§ 8.6. Логический тип данных. Логическое выражение

Школьный курс python
Содержание

О типе bool

В языке C++ существует логический тип данных bool. Переменные этого типа могут содержать всего два значения – true (истина) и false (ложь). true и false являются логическими литералами. В С++ true интерпретируется, как 1, а false как 0. Логический тип относится к целым типам. Этот тип данных назван в честь Дж. Буля, разработавшего математическое представление законов логики. Поэтому переменные этого типа часто называются булевскими или логическими.
За счет того, что любое арифметическое выражение можно использовать в качестве логического выражения, код программы становится еще более компактным.
По умолчанию значения логических переменных выводятся в числовом представлении. Для вывода в текстовом виде необходимо использовать манипулятор boolalpha:

    bool f, q = true, k = false;
    cout << boolalpha << true << endl;
    f = k;
    cout << q << " " << f << endl;
    cout << noboolalpha << k << endl;
Манипулятор noboolalpha отменяет вывод логического значения в текстовом виде и возвращает числовое представление.

Операции отношения (сравнения)

Операции отношения – это бинарные операции сравнивающие два значения. В С++ определены следующие операции сравнения:

<   меньше
<=  меньше либо равно
>   больше
>=  больше либо равно
==  равно
!=  не равно
Пробелы между символами не допускаются!

В качестве операндов могут выступать константы, переменные и сложные выражения, включающие различные операции и функции. Результатом сравнения двух выражений является true или false. Например:

int a = 10, b = 5;
cout << boolalpha
     << (a > b) << "\n"      // (true)
     << (b % a == 0) << "\n" // (false)
     << (b * a != 0) << "\n" // (true)
     << (b / a >= 2) << "\n" // (false)
     << (a / b != 0) << "\n" // (true)
     << (b == 2 * a)         // (false)
     << endl;

Поскольку арифметические операции обладают большим приоритетом, чем операция "<<", скобки необходимы.
Задача 1. Дана координатная плоскость и прямая на ней. Составить программу, которая выводит значение true, если точка находится в заштрихованной области (справа от прямой).

Программа 8.6.1
#include <iostream>
using namespace std;

int main() {
    int x;
    cout << "x = "; cin >> x;
    cout << boolalpha
         << (x > 2)
         << endl;
    return 0;
}

Задача 2. Поле шахматной доски определяется парой натуральных чисел, не превосходящих 8: первое число x — номер поля по горизонтали (при счете слева направо), второе число y — номер поля по вертикали (при счете снизу вверх). Даны натуральные числа x1 и y1 - позиция фигуры слона. Составить программу которая выводит true, если слон угрожает полю (x2, y2).

Программа 8.6.2
#include <iostream>
using namespace std;

int main() {
    int x1, x2, y1, y2;
    cout << "x1 = "; cin >> x1;
    cout << "y1 = "; cin >> y1;
    cout << "x2 = "; cin >> x2;
    cout << "y2 = "; cin >> y2;
    cout << boolalpha
         << (abs(x1-x2) == abs(y1-y2))
         << endl;
    return 0;
}

Вывод

x1 = 4
y1 = 4
x2 = 6
y2 = 5
false

Идея алгоритма заключается в следующем: если абсолютные значения разности соответствующих координат по х: x1 и x2 и по y: y1 и y2 будут равны, то слон будет угрожать этому полю (выводится значение true).
Очень распространенной ошибкой является использование в качестве логическое выражения a = b (т. е. операцию присваивания), вместо a == b (операции сравнения на равенство). Но для C++ применение операции = в условиях - допустимо! Например:

cout << (a == b) << endl;
cout << bool(a = b) << endl;

В этом фрагменте последняя инструкция будет выводить значения true в любом случае, если b != 0. Понимать эту инструкцию нужно следующим образом: вначале переменной a присваивается значение b. Затем результат преобразуется к типу bool (любое ненулевое значение будет рано true).

Логические операции && ("и"), || ("или"), ! ("не")

  • Логическая операция && реализует булевскую операцию “И” (конъюнкция, логическое умножение). Эта операция бинарная, т. е. имеет два операнда, в качестве которых могут выступать, например, операции сравнения. Результат логического выражения true, если оба операнда истинны.
  • Логическая операция || реализует булевскую операцию “ИЛИ” (дизъюнкция, логическое сложение). Эта операция тоже является бинарной. Результат логического выражения false, если оба операнда ложны.
  • Логическая операция ! реализует булевскую операцию “НЕ” или логическое отрицание (инверсия). Эта операция является унарной (выполняется над одним операндом). Результат true, если операнд имеет значение false, и наоборот.
#include <iostream>
using namespace std;

int main() {
    int a = 2, b = 4;
    cout << boolalpha
         << (b < a && b * b == a) << "\n"       //  (false)
         << (a % 2 == 0 || b % a != 0) << "\n"  //  (true)
         << !(a == 7) // эквивалентно a != 7        (true)
         << endl;
    return 0;
}

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

a % 2 == 0

или так:

!(a % 2)
Если a = 10, то в обоих случаях выражения вернут значение true. Почему так? Выражение a % 2, в этом случае, вернет 0, что интерпретируется как false. А !, в свою очередь, инвертирует значение в true. Второй вариант выглядит более компактным, поэтому используется чаще.

Задача 3. Дана координатная плоскость и три прямых на ней. Составить программу, которая выводит значение true, если точка находится в заштрихованной области (ограниченной этими прямыми).

Программа 8.6.3
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
	cout << boolalpha
		 << (x >= -3 && x < 1 && y < 3) 
		 << endl;
    return 0;
}

Вывод

x = 3
y = 1
false

Рассмотрим более сложный пример.
Задача 4. Дана точка A с координатами (x, y). Составить программу, которая печатает True, если точка принадлежит заштрихованной области, и false в противном случае.

Прежде чем решать данную задачу, мы должны определить уравнения для двух прямых и кривой в первой четверти. Уравнение прямой, проходящей через точки (-5;0) и (0;5): y = x + 5. Уравнение прямой, проходящей через точки (-5;0) и (0;-5): y = -x - 5. Кривая в первой четверти представляет собой дугу окружности с центром в начале координат. Уравнение такой окружности: r2 = x2 + y2. Поскольку радиус окружности равен 5, то уравнение примет вид x2 + y2 = 25. Вывод формулы уравнения окружности и определение уравнения прямой смотрите ниже, под спойлером "Примеры решения задач".
Программа 8.6.4
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
	cout << boolalpha
		 << (y < x + 5  &&
		     y > -x - 5 &&
		     x < 0 ||
		     x * x + y * y < 25 &&
		     x > 0 &&
		     y > 0) 
		 << endl;
    return 0;
}

Вывод

x = 2
y = -2
false

Логическое выражение в этой задаче необходимо разбить на две части. Первая часть описывает область в виде треугольника, слева от оси y. А вторая - описывает сектор окружности в первой четверти. Поскольку точка может находиться либо в первой области, либо во второй - они связаны логической операцией ||.

Приоритет логических операций

В языке программирования C++ логические операции имеют следующий приоритет по возрастанию:

Операция Описание
?: Условное выражение
|| Булевское «или»
&& Булевское «и»
==, != Сравнение на равенство и неравенство
>, >= Сравнение на > и >=
<, <= Сравнение на < и <=
<=> Трехстороннее сравнение
! Булевское "не"

Ассоциативность логических операций - слева на право, кроме "!". На этом основаны "ленивые вычисления". Принцип "ленивых" вычислений заключается в следующем. Если операции || или && возвращают значение достаточное для вычисления всего выражения (false для первого операнда, в случае с &&, и true для первого операнда, в случае с ||), то вычисления останавливаются и возвращается результат.
Заметим, что все арифметические операции имеют больший приоритет по сравнению с логическими, поэтому, в программах выше, выражения с арифметическими операциями не заключались в отдельные скобки.

Логические выражения и законы Булевой алгебры

Длинные выражения можно упростить, если использовать законы Булевой алгебры. Приведем пример.

В этой задаче использовался распределительный (дистрибутивный) закон для "или":
A ^ B v A ^ C = A ^ (B v C)

Задача 5. Дана точка A с координатами (x, y). Составить программу, которая печатает true, если точка принадлежит заштрихованной области, и false в противном случае.

Исходное логическое выражение имеет вид:

(x * x + y * y < 25 && x < -3) || (x * x + y * y < 25 && x > 3)

Если применить дистрибутивный закон, то можно это выражение сделать значительно короче, как показано в программе 8.6.5.

Программа 8.6.5
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
	cout << boolalpha
		 << (x * x + y * y < 25 &&
			(x < -3 || x > 3))
		 << endl;
    return 0;
}

Вывод

x = 5
y = 3
false

Однако, в данном случае, скобки всё же нужны! Если во втором операнде при && убрать скобки, то выражение:

x * x + y * y < 25 && x < -3 || x > 3

вернёт true, при тех же исходных данных. Часть этого выражения, до операции || (ввиду старшинства &&), является левым операндом ||. Поскольку логическая операция || возвращает true, если хотя бы один из операндов имеет значение true, то любое значение x > 3 (расположенного за ограничивающей дугой окружности) приведет к тому, что выражение, в целом, всегда будет истинно. Будьте внимательны при составлении логических выражений!

Приложение

Примеры решения задач
Задача 6. Дана координатная плоскость и прямая на ней. Составить программу, которая выводит значение true, если точка находится в заштрихованной области.

Для решения задачи необходимо составить уравнение прямой:

Коэффициенты k и b можно пределить по координатам пресечения осей x и y. Прямая пересекает оси в точках (0;3) и (3;0). Определим коэффициент b. Подставим в уравнение прямой значения координат x = 0, y = 3. Получаем b = 3. Определим коэффициент k. Подставим в уравнение прямой значения координат x = 3, y = 0 и полученное значение b. Получаем k = -1. Следовательно, уравнение этой прямой:

y = -x + 3

Так как заштрихованная область находится ниже этой прямой, то y < -x + 3. Учитывая, что заштрихованная область находится правее оси y и выше оси x, программу можно составить так:

Программа 8.6.6
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
	cout << boolalpha
		 << (y < -x + 3 &&
			 y > 0 && 
			 x > 0)
		 << endl;
    return 0;
}

Задача 7. На координатной плоскости даны две окружности с общим центром в точке (0;-1) с радиусами r1 = 5 и r2 = 3 и прямая y = 1. Дана точка A с координатами (x, y). Составить программу, которая печатает true, если точка принадлежит заштрихованной области, и false в противном случае.

Для решения задачи выясним, как получить уравнение окружности. Рассмотрим систему координат в которой построена окружность с центром в точке P(x0;y0) и радиусом r. Пусть A - точка лежащая на окружности с координатами (x;y).

Отрезки r, x - x0 и y - y0 образуют прямоугольный треугольник, где r - его гипотенуза, а x - x0 и y - y0 - его катеты. Тогда по теореме Пифагора:

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

x2 + (y + 1)2 = 25
x2 + (y + 1)2 = 9

Так как заштрихованная область находится ниже окружности с радиусом r' = 5, но выше окружности с радиусом r'' = 3, логические выражения примут вид:

x2 + (y + 1)2 < 25
x2 + (y + 1)2 > 9

При составлении итогового логического выражения учитываем, что заштрихованная область находится выше прямой y = 1. Таким образом, программа может быть составлена следующим образом:

Программа 8.6.7
#include <iostream>
using namespace std;

int main() {
    double x, y;
    cout << "x = "; cin >> x;
    cout << "y = "; cin >> y;
	cout << boolalpha
		 << (x * x + (y + 1) * (y + 1) < 25 &&
			 x * x + (y + 1) * (y + 1) > 9  &&
			 y > 1)
		 << endl;
    return 0;
}
Вопросы
Темы сообщений
Задания А
Задания Б
Задания С
Ссылки
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (2 оценок, среднее: 5,00 из 5)
Загрузка...

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.


Обсуждение закрыто.