Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Выполнение логических операций
Зачем нужны логические операторы Использование простых логических операторов Бинарные числа в C++ Выполнение битовых логических операций
аиболее синтаксической конструкцией C++ является выра- жение. Большинство используемых выражений содержит опе- раторы сложения (+), вычитания (-) и умножения {*). В данной описаны все эти типы выражений. Существует целый класс так называемых логических операторов. В отличие от арифметических, этот тип операторов многими не воспринимается как операторы. Неправда, что люди не сталкиваются с логическими операторами. Значения опера- торов И и ИЛИ они вычисляют постоянно. Я не буду есть овсянки без молока И са- хара. И закажу себе ром ИЛИ шотландский виски. Как видите, люди очень часто ис- пользуют логические операторы, не осознавая этого. Логические операторы бывают двух типов. Операторы И и ИЛИ называются про- стыми логическими операторами. Операторы второго типа, или битовые операторы, уникальны, так как используются только в программировании. Этот тип операторов позволяет работать с любым битом в машинном представлении числа.
Зачем логические У вас может возникнуть вопрос: "Если до сегодняшнего дня меня совершенно не волновали логические операторы, почему это должно случиться теперь?'1. Да потому, что программы должны "уметь" принимать решения. Программы, написанные принятия решений, по сложности подобны приведенной в первой главе (вспомните, что все выполняемые ею действия совершенно Для принятия ре- шений в программах просто необходимо использовать логические операторы.
использование логических Программы на C++ должны обладать способностью принимать решения. Про- грамма Convert не выполняла ничего, кроме простого преобразования значений тем- пературы, и не принимала никаких решений, основанных на входных значениях. Для принятия таких решений в программах C++ используют логические операторы. Простые логические операторы приведены в табл. 4.1. Они могут возвращать два значения: tru e (истина) и fals e (ложь).
44 Часть Первое знакомство с C++ Таблица Простыеоператорыизповседневнойлогики ОПЕРАТОР ЗНАЧЕНИЕ
Равенство; истинно, когда значение левого аргумента совпадает со значением правого Неравенство; противоположно равенству > , < Больше, меньше; истинно, когда значение левого выражения больше меньше) зна- ченияправого >= , Больше или равно, меньше или равно; истинно, если истиной является > или (соответственно < или И; истинно, если аргументы и слева и справа являются истиной I I ИЛИ; истинно, если или левый, или правый аргумент являются истиной ! НЕ; истинно, если его аргумент принимает ложное значение
Первые шесть операторов табл. 4.1 являются операторами сравнения. Оператор ра- венства используется для проверки равенства двух значений. Например, следующее выражение истинно, если значением п является 0, и ложно во всех других случаях: п == 0;
Не перепутайте оператор равенства == с оператором присвоения =. Эта ошибка очень распространена, к тому же компилятор C++, вообще говоря, не считает ее ошибкой, что делает ее вдвойне опасной!
п //' Программист хотел что п == О Широко распространены в повседневной жизни операторы "больше" (>) и (<). Приведем пример логического выражения, возвращающего значение true . in t in t n2 = 2; n l < n2 Операторы "больше" и "меньше" внешне очень похожи, и поэтому их легко пере- путать. Чтобы этого не случилось, помните, что оператор-стрелочка принимает значе- ние tru e в том случае, когда из двух сравниваемых значений он указывает на меньшее. С помощью операторов > и < можно найти случаи, когда nl больше или меньше п2, однако при этом игнорируется возможность равенства их значений. Операторы "больше или равно" "меньше или равно" в отличие от только что рассмот- ренных, учитывают и эту возможность. Так же широко используются и операторы (И) и | | Эти операторы обычно сочетаются с другими логическими операторами: истинно, если п2 больше nl и меньше пЗ (nl < (п2 < пЗ) ; В качестве ремарки: оператор "больше или равно" можно определить как nl <= n2 эквивалентно (nl < (nl
Логические операции и действительные переменные Переменные с плавающей точкой, как уже отмечалось, не могут использоваться для перечисления. Вы можете сказать: первый, второй, третий, четвертый и т.д., так
качестве еще ремарки: операторы сравнения вообще достаточно взаимоза- меняемы. Так, например, эквивалентно (! (а>Ь) &&! — Прим. ред. Глава 4. Выполнение логических операций 45 как соотношения между 1, 2, 3 абсолютно точно известны. Но нет никакого смысла говорить о номере 4.535887 в последовательности (такой способ нумерации возможен лишь как обозначение чего-то между четвертым и пятым, но не действительного зна~ чения номера, так как в любом сколь угодно малом отрезке их множество). Тип представляющий в C++ действительные числа, не является перечис- лимы.м. Кроме того, в отличие от чисел, числа с плавающей точкой имеют ограниченное количество разрядов, поэтому при использовании операторов сравнения с числами с плавающей точкой необходимо соблюдать осторожность. Рас- смотрим следующий пример: float fl float f2 10.0; fl / 3; fl== (f2 * 3 0) / Равны ли значения? Сравнивая начальное и полученное значения, мы не обязательно получим равен- ство. Действительные переменные, с которыми работает компьютер, не могут содер- жать бесконечного числа значимых разрядов. Поэтому равняется, например, 3.3333, а не В отличие от математики, в компьютере число троек после точки ограничено. Умножив 3.3333 на 3, вы, вероятно, получите не 10.0, а 9.9999. Такой маленькой разницей может пренебречь человек, но не компьютер. Эта машина пони- мает под равенством исключительно точное равенство значений. В современных процессорах выполнение таких вычислений очень усложнено. Процессор может даже устранить ошибку округления, но точно определить, когда именно процессору вздумается это сделать, язык C++ не способен. Проблемы могут появиться и при совершенно простых вычислениях, например: float fl = 10.0; f2 = 120 % 11; //истинно ли это выражение? Теоретически f 1 и f 2 должны быть равны (об операции деления по модулю можно прочитать в главе 3, "Выполнение математических операций"). Ошибка округления возникнуть вроде бы не должна. Однако и в этом нельзя быть уверенным: вам ведь не- известно, как именно представляются числа с плавающей точкой внутри компьютера. Позвольте порекомендовать более безопасное сравнение: floa t f l = 10.0 ; floa t f2 = fl / 3; floa t f3 = f2 * 3.0 ; (f l - f3) < 0.000 1 SS (f 3 - fl ) < Оно ИСТИННО В ТОМ случае, если разница между f 1 и f2 меньше какого-то малого значения (в нашем случае — 0.0001); при этом небольшие погрешности вычислений на правильность сравнения не повлияют. Сокращенные вычисления в C++ Рассмотрим следующую конструкцию:
Если условие1 ложно, то результат не будет истинным, независимо от истинно- сти выражения условие2. В схеме условие1 || условие2 в случае истинности выражения неважно, какое значение принимает усло- вие2, — результат будет истинным.
Более того, в данном случае это не красивое слово, а строгий математический термин. — Прим. ред. 46 Часть /. Первое знакомство с C++ Для экономии времени C++ вычисляет первым условие]., и в случае, если оно ложно (для оператора или истинно (для оператора I |) , выражение не вычисляется и не анализируется. Типы логических переменных Поскольку > является оператором, то сравнение а > 10 представляет собой выра- жение. Очевидно, что результатом такого выражения может быть или tru e (истина), или fals e (ложь). Вы уже могли заметить, что среди обсуждаемых в главе 2, "Премудрости объявле- ния переменных", типов переменных не было логических (булевых) типов. Более то- го, ни в одном из существующих типов C++ нет значений tru e или false . Тогда к какому типу отнести выражение а > 10? В C++ для хранения логических значений используется тип int . При этом 0 обо- значает false , а любое другое отличное от нуля значение является истиной (true). Вы- ражения типа а > 10 могут принимать значения 0 (false) или, например, 1 (true). Microsoft Visual Basic для интерпретации значений fals e и tru e также ис- пользует целые числа, но в нем операторы сравнения возвращают или 0 (false) , или -1 (true) .
В новом стандарте ANSI C++ для работы с булевыми переменными определен тип имеющий значения tru e и false .
'Бшифнме числа C++ Переменные хранятся в компьютере в виде так называемых двоичных, или бинар- ных, чисел, т.е. представлены в виде последовательности битов, каждый из которых может содержать два значения: 0 или 1. Скорее всего, вам не придется оперировать с числами на битовом уровне, хотя существуют ситуации, когда обойтись без этого нельзя. снабжен несколькими операторами для подобных целей. Вряд ли вам придется часто работать с переменными на битовом уровне, поэтому остальную часть главы следует рассматривать как техническое от- ступление от основного повествования. Так называемые битовые логические операторы работают с аргументами на бито- вом уровне. Для того чтобы понять принципы их работы, давайте рассмотрим, как компьютер хранит переменные.
Десятичная система счисления Числа, которыми мы чаще всего пользуемся, называются или числа- ми по основанию 10. В основном программисты на C++ тоже используют десятичные переменные. Например, мы говорим, что значение переменной var равно 123. Число 123 можно представить в виде При этом каждое из чисел 100, 10, 1 является степенью 10.
123 = 1 * 100 + 2 * 10 + 3 * 1, что эквивалентно следующему: 123 = 1 * + 2 * + 3 * 10° Помните, что любое число в нулевой степени равняется 1. Глава 4. Выполнение логических операций 47 Другие системы счисления Использование числа 10 в качестве основания нашей системы счисления объясня- ется, по всей вероятности, тем, что издревле для подсчетов человек использовал паль- цы рук. Учитывая особенности нашей физиологии, удобной альтернативной системой счисления можно было бы выбрать с основанием 20). Если бы наша вычислительная система была заимствована у собак, то она бы была восьмеричной (еше один "разряд", находящийся на задней части каждой лапы, учитывается). Эта система счисления работала бы менее хорошо: = 1 8'" + 7 + 3 * = Индексы 10 и 8 указывают систему счисления: 10 — десятичная. 8 — восьмерич- ная. Основанием системы счисления может быть любое положительное число.
Двоичная система счисления У компьютеров, видимо, пальцев поменьше (может быть, поэтому они такие неда- лекие?). Они предпочитают пользоваться двоичной системой счисления. Число 123 переводится в двоичную систему таким образом: 12 + + 1*3 2 + + 0* 4 + 1* 2 + 1* 1 = Существует соглашение, которое гласит, что в записи двоичных чисел используют- ся 4, 8, 16 или 32 (и т.д.) двоичных цифр, даже если старшие цифры — нули. Внут- реннее представление числа в компьютере строится именно таким образом. Понятие разряда применяется к числам, кратным десяти, двоичный же разряд на- зывается битом. Восемь битов составляют байт, а слово представляется или двумя, или четырьмя байтами. Поскольку основа двоичной системы счисления очень мала, для представления чи- сел необходимо использовать слишком большое количество битов. Для представления таких обычных чисел, как неудобно использовать выражения вида Поэтому программисты предпочитают представлять числа блоками из четырех битов. С помощью одного четырехбитового блока можно представить любое число от 0 до 15, и такая система счисления называется шестнадцатеричной т.е. сис- темой по основанию 16. Часто употребляют ее сокращенное название hex. В шестнадцатеричной системе обозначения цифр от 0 до 9 остаются теми же, а числа от 10 до 15 представляются с помощью первых шести букв алфавита: А вместо 10, в вместо 11 и т. д. Следовательно, — это 12 3 7 * 16 1 + = Поскольку программисты предпочитают представлять числа с помощью 4, 8, 16 или 32 битов, шестнадцатеричные числа состоят соответственно из 1, 2, 4 или 8 шест- надцатеричных разрядов (даже если ведущие разряды равны 0). В заключение замечу, что, так как терминал не поддерживает нижний индекс, за- писывать шестнадцатеричные символы в виде неудобно. Даже в том текстовом редакторе, который я использую сейчас, довольно неудобно всякий раз менять мы шрифтов для ввода всего двух символов. Поэтому программисты договорились на- чинать шестнадцатеричные числа с 0х (это странное обозначение было придумано еще во время разработки языка С). Таким образом, равно 0х7в. Следуя этому соглашению, равно 123, тогда как 0x123 равно 291. К шестнадцатеричным числам можно применять все те же математические опера- торы, что и к десятичным. Нам трудно выполнить в уме умножение чисел Схс*СхЕ потому, что таблица умножения, которую мы учили в школе, применима только к де- сятичной системе счисления.
12 Что и было сделано у некоторых народов, например у майя или — Прим. ред. 48 Часть \. Первое знакомство с C++ Выражения с римскими числами Интересно, что некоторые системы чисел значительно препятствовали развитию математики, К таким относится и так называемая римская система. Сложить два римских числа не очень сложно: XIX + XXVI = XXV Последовательность выполнения сложения такова: после V "уничтожает" I перед х, поэтому в результате получаем XV; б) если добавить еще один х, получим хххх, или XL. Сложность вычитания римских чисел приблизительно такая же. Однако, чтобы умножить два римских числа, требуется диплом бакалавра математики (у вас воло- сы станут дыбом от правила, которое объясняет, как добавить к X разряд справа так, чтобы равнялось XL). А уж о делении римских чисел можно писать це- лые докторские диссертации...
Выполнение логических Все числа C++ могут быть представлены в двоичном виде, т.е. с использованием только 0 и I в записи числа. В табл. 4.2 указаны операции, которые работают с чис- лами побитово; отсюда и происходит название термина "битовые операции". Таблица Битовыеоперации ОПЕРАТОР ФУНКЦИЯ
Каждый бит меняет свое значение на противоположное: 0 заменяется нулем Битовое И: поочередно выполняет операцию И с парами битов левого и правого аргумента I Битовое ИЛИ Битовое исключающее ИЛИ
С помощью битовых операций можно сохранять большое количество информа- ции в маленьком участке памяти. В мире существует множество вещей, которые имеют только два состояния (или, максимум, четыре). Вы или женаты (замужем), или нет (хотя можете быть в разводе или еще не женаты). Вы или мужчина, или женщина (по крайней мере, так сказано в моих водительских правах). В C++ каж- дую такую характеристику вы можете сохранить в одном бите. Таким образом, по- скольку для хранения целого числа выделяется 4 байта, в тип in t можно упаковать значения 32 разных свойств. Кроме того, битовые операции выполняются крайне быстро. Хранение 32 характе- ристик в одном типе не приводит ни к каким дополнительным затратам. Битовые операции с одним битом Битовые операторы &, | и выполняют логические операции над отдельными би- тами числа. Если рассматривать 0 как fals e и 1 как tru e (так принято, хотя можно ввести и другие обозначения), то для оператора справедливо следующее: ~l(true ) равно (true) равно (false ) Глава 4. Выполнение логических операций 49 Оператор & определяется так: l(true) & 1 (true) равно l(true) 1 (true) & 0 (false) равно 5 0 (false) равно 0 (false) & 1 (true) равно Для оператора |: l(true) 1 (true) равно l(true) 1 (true) 0 (false) равно (false) 0 (false) равно (false) ! 1 (true) равно Для последнего логического оператора, называемого "исключающим или" прямой аналог в повседневной жизни найти труднее. Он возвращает значение true , если истинным является какой-то один (но не оба!) из его аргументов. Таблица ис- тинности этого оператора представлена ниже (табл. 4.3). Таблица4.3.Таблицаистинностиоператора О _ _ О 1 О Теперь, зная, как работают эти операторы с отдельными битами, рассмотрим их применение к двоичным числам. |
Последнее изменение этой страницы: 2019-04-19; Просмотров: 261; Нарушение авторского права страницы