View on GitHub

Курс по C++

Базовые конспекты по программированию на C++ для групп 371ПС, 372ПС. В конспектах ОЧЕНЬ много неточностей, ошибок. Правки приветствуются =)

Основные понятия булевой логики.

Основные логические операции

Все логические операции в контексте C++ применимы исключительно для значений с логическим типом данных —bool. В случае, когда в условии или логическом выражении оказывается тип данных отличный от логического, язык будет пытаться приводить используемый тип к bool (иногда успешно, а иногда нет).

NOT

Логическая операция НЕ представима в виде оператора !. Эта операция “отрицает” значение которое вы ей передаёте.

Таблица истинности будет выглядеть подобным образом:

X !X
0 1
1 0

Рассмотрим фрагмент кода с примерами работы:

cout << (!true); //false
cout << (!(!true));//true
cout << (!(10 > 5));//false

AND

Логическая операция И представима в виде оператора &&. Для этой операции существует единственный набор входных параметров, при котором она принимает значение ИСТИНА . Это набор, в котором оба параметра истинны.

Таблица истинности будет выглядеть подобным образом:

X Y X && Y
0 0 0
0 1 0
1 0 0
1 1 1

Рассмотрим фрагмент кода с примерами работы:

cout << (true && false); //false
cout << (true && !false);//true
cout << ((10 > 5) && 1);//true
cout << ((x > 5) && (x <= 5));//false

OR

Логическая операция ИЛИ представима в виде оператора ||. Для этой операции существует единственный набор входных параметров, при котором она принимает значение ЛОЖЬ . Это набор, в котором оба параметра ложны.

Таблица истинности будет выглядеть подобным образом:

X Y X || Y
0 0 0
0 1 1
1 0 1
1 1 1

Рассмотрим фрагмент кода с примерами работы:

cout << (true || false); //true
cout << (true || !false);//true
cout << (!(10 > 5) || 0);//false
cout << ((x > 5) || (x <= 5));// true

Импликация

В C++ на примитивном уровне не реализована, но легко заменяется с помощью выражения !X OR Y. Эта операция выполняет функцию операции следовательно. Из X следует Y. Если верен X, то верен должен быть и Y. Если X ложен, то Y может быть любым.

Из истины может следовать только истина, а из лжи всё что угодно.

Таблица истинности будет выглядеть подобным образом: |X|Y|X -> Y| |:—:|:—:|:—:| |0|0|1| |0|1|1| |1|0|0| |1|1|1|

Equals

Логическая операция РАВНО представима в виде оператора ==. Суть операции в совпадении значений двух параметров, которые в неё передаются. Отрицание эквивалентности можно записать как !=.

Таблица истинности будет выглядеть подобным образом:

X Y X == Y
0 0 1
0 1 0
1 0 0
1 1 1

Рассмотрим фрагмент кода с примерами работы:

cout << (true == false); //false
cout << (true == !false);//true
cout << ((10 > 5) == 1);//true
cout << ((x > 5) != (x <= 5));//true

XOR

Логическая операция ИСКЛЮЧАЮЩЕЕ ИЛИ представима в виде оператора ^. Для корректного использования этой операции в логических выражениях нужно использовать только логические типы или приведение. Суть операции в том, что значение только одного параметра может быть истинным.

Таблица истинности будет выглядеть подобным образом:

X Y X ^ Y
0 0 0
0 1 1
1 0 1
1 1 0

Рассмотрим фрагмент кода с примерами работы:

cout << (true ^ false); //true
cout << (true ^ !false);//false
cout << ((10 > 5) ^ bool(25));//false
cout << ((x > 5) ^ (x <= 5));//true

Булевы тождества и их проверка. Таблицы истинности.

При написании собственных булевых тождеств или функций необходимо делать проверку. Её осуществляют с помощью таблицы истинности. Такая таблица содержит в себе все возможные значения параметров и функции/тождества. Рассмотрим таблицу для функции $F = X_1andX_2orX_3$

X1 X2 X3 F
0 0 0 0
0 0 1 1
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1

Законы булевой логики (свойства логических операций).

Основными законами считаются:

Будьте ВНИМАТЕЛЬНЫ при составлении и упрощении ваших условий.

Представление целых чисел в памяти компьютера.

Большинство современных компьютеров используют двоичную логику и производят вычисления в двоичной системе счисления. Типичное число в двоичной системе выглядит так: 1110 1111. Перевод из двоичной в десятичную и обратно выполняется очень просто.

Значение при переводе вычисляется по формуле: $ 2^{i}{k_i} $, где k – значение бита, а i – позиция бита в числе.

Позиция бита Значение бита Значение при переводе
0 1 1
1 1 2
2 1 4
3 1 8
4 0 0
5 1 32
6 1 64
7 1 128

Значение числа $111011112=1+2+4+8+0+64+128 =239{10}$

Переполнение

У каждой переменной будь она целочисленная или с плавающей точкой есть память, которую она занимает. Метод хранения и объем этой памяти напрямую влияют на то какие числа туда можно помещать.

Допустим, что в ячейке размером 4 бита лежит число 15 (максимально возможное). $1111_2$

Если мы попробуем прибавить к этому числу 1, то по логике должны получить 16, но т.к. на хранение выделено только 4 бита, мы получаем 0. $0|1111_2+1=1|0000_2$

Битовые операции над целыми числами и их применения.

Набор битовых операция будет очень сильно напоминать набор логических. Разница лишь в том, что битовые операции можно применять к целым числам.

При использовании все эти операторы будут возвращать число, полученное побитовым применением соответствующей логической операции к битам параметров.

Например:

cout << (255 & 1);//1
cout << (255 | 0);//255
cout << (255 ^ 128);//127
cout << (~0);//-1

Сдвиг влево и сдвиг вправо

Сдвиг влево и сдвиг право — внезапно побитово сдвигают число влево или в право, тем самым умножая («) или деля (») его на 2. Является “быстрым” целочисленным умножением/делением на 2.

Условный оператор.

Конструкции if и if else.

В языке С++ существуют конструкции, которые называются условиями. Они записываются как if:

if(true)
{
	//код выполняется
}
if(false)
{
	//код НЕ выполняется
}

Условие состоит из нескольких частей:

if(условие)
{
	тело условия - часть программы, которая будет 
	выполняться исключительно при истинности условия.
}

Пример:

cin >> x;
if(x % 2 == 0)
{
	cout << "X is even!";
}
else 
{
	cout << "X is odd!";
}

Часть программы заключенная между фигурными скобками { } называется БЛОКОМ КОДА или *ОБЛАСТЬЮ ВИДИМОСТИ

После блока условия можно воспользоваться конструкцией else, блок кода, относящийся к нему, будет исполняться только при условии, что условие в if было ложным. Таким же образом можно составлять достаточно длинные и сложные конструкции с else if.

Например:

if(apple == "green")
{
	cout << "This apple is GREEN!";
}
else if(apple == "red")/*Здесь можно было бы обойтись и без else,
 но тогда программе бы пришлось выполнять много ненужных сравнений.*/
{
	cout << "This apple is RED!";  
}
else if (apple == "purple")
{
	cout << "This apple is not an apple at all!";
}
else 
{
	cout << "It`s a banana >:D";
}

Вы можете ставить сколько угодно else if после if, но else может быть только один и должен стоять на ** последнем месте**.

Вложенные условные операторы.

При необходимости обрабатывать длинные и сложные условия вы можете “вкладывать” условные конструкции друг в друга. Например:

if(shape == "sphere")
{
	if(color == "blue")
	{
		cout << "It`s a whale!";
	}
	else if (color == "green")
	{
		cout << "It's a watermelon!";
	}
}
else if (shape == "cube")
{
	cout << "It`s a box!";
}

Объединение условий (and, or, not).

Так как в условие для if можно записать любое логическое тождество, то для составления сложных условий нужно пользоваться логическими операторами для того, что бы не сильно увеличивать вложенность и улучшить читабельность. Запишем проверку Число Х делится на 3, на 5 или не делится на 10.

Без составного условия:

if(x % 3 == 0)
{
	if(x % 5 == 0)
	{
		//ваш код
	}
	else if(x % 10 != 0)
	{
		//ваш код
	}
}
else if(x % 10 != 0)
{
	//ваш код
}

С составным условием:

 if(x % 3 == 0 && x % 5 == 0 || x % 10 != 0)
 {
	 //ваш код
 }

Вопросов “Зачем?” возникать не должно…

При проверке длинной “колбасы” из условий, разделённых с помощью операции ||, программа прекратит проверку и зайдёт в блок при первой встрече значения ИСТИНА. Аналогично и для операции && и значения ЛОЖЬ — программа ** прекратит расчёт** следующих условий, и вход выполнен не будет.

Пример:

if(true && (true||...) && false && ...)/*с помощью многоточий
 показаны места, которые не будут рассчитаны*/
{
}

Оптимизация логических выражений компилятором (false and X, true or Y).

В случае, когда результат выражения в условии известен до запуска программы, компилятор может упростить всё условие или даже весь блок кода. Пример:

if(true || x < 10 && x < 93021 && false)
{
	//всегда будет выполняться
}

Оператор Case.

Существует ещё одна конструкция, позволяющая обрабатывать условия.

switch (x)
{
case 1:
	cout << "X == 1";
	break;
case 2:
	cout << "X == 2";
	break;
case 3:
	cout << "X == 3";
	break;
default:
	cout << "X != 1, 2, 3.";
};

В скобках у switch указываем переменную, значения которой хотим обрабатывать. И дальше перечисляем необходимые значения этой переменной в case. default будет выполняться, если ни одно условие не было выполнено. Важно : если не ставить break; после необходимых вам операций, то выполнение пойдёт просто “вниз” до первого break;.

x = 1;
switch(x)
{
	case 1:
		cout << 1;
	case 2:
		cout << 2;
		break;
	case 3:
		cout << 3;
};  

Вывод программы будет 12.