Краткое содержание
Этот урок открывает третий раздел курса, посвящённый выражениям и их операторам. Он объясняет, для чего нужен раздел: научить строить выражения, значение которых можно предсказать с уверенностью, зная, какая операция выполняется первой, какого типа результат, какие у него побочные эффекты и какие выражения не имеют смысла; представляет четыре урока раздела и связывающую их нить, от целочисленной и вещественной арифметики до битов и математической библиотеки, через условия и каталог неопределённого поведения; напоминает то, что раздел считает известным из второго, а именно тип каждого значения, его пределы и его преобразования; формулирует задачу, которую решает раздел, задачу программы, которая компилируется без единого предупреждения и чьи ответы на шесть школьных вопросов все неверны, если вообще есть; и показывает, куда он ведёт, в следующих разделах и в курсе «Программирование на C++ II».
Цели обучения
- Описывать последовательность содержания раздела и объяснять, что каждый урок даёт уроку, который идёт за ним.
- Вспоминать необходимое из раздела 2 (целые и вещественные типы, их диапазоны значений, переполнение и преобразования) и при необходимости повторять это.
- Предвидеть на примере, что значение выражения зависит от правил вычисления (приоритета, типа операндов, порядка эффектов), которые не всегда совпадают с правилами школьной математики.
- Понимать, что ожидается уметь к концу раздела, и отличать это от того, что будет изучено в следующих разделах.
Входная проверка
Прежде чем проходить раздел, полезно определить исходный уровень. Эта проверка является самопроверкой: она не оценивается, и её единственная цель состоит в том, чтобы направить занятия. Первые четыре вопроса касаются того, что раздел считает известным из второго: целочисленного деления, записи в двоичной системе, беззнакового вычитания и знакового переполнения. Следующие шесть в порядке уроков касаются центральных идей раздела, и некоторые из них исходят из школьной математики или из элементарной логики. Никто не обязан пока отвечать на них верно, а в двух из них «пока не знаю» является честным ответом: каждый ответ, верный или нет, объясняет суть дела и называет урок, где она разбирается. Те же умения измеряются снова в конце, в уроке итогов.
Перед началом раздела оцени свою отправную точку. Это короткая самопроверка: она не оценивается, а результат хранится только в твоём браузере.
Вопрос 1Из предыдущих разделовПрограмма объявляет
const double r{7 / 2};и выводитr. Что появится на экране?Считает, что способ деления определяет тип переменной; его определяет тип операндов.Считает, что целочисленное деление округляет; на самом деле оно отбрасывает дробную часть.Значение 3 постоянно и точно представимо вdouble: никакого сужения, которое нужно было бы отвергнуть, нет.Деление7 / 2выполняется над целыми числами и даёт целое частное, 3; лишь затем это 3 преобразуется вdouble. Операцию определяет тип операндов, а не тип переменной, которая получает результат. Урок 3.1 превращает это наблюдение в общее правило: тип определяется в каждом узле выражения.Повторить: Символы, логические значения, преобразования и константы
Вопрос 2Из предыдущих разделовКак записать число 13 в двоичной системе восемью битами?
Неверно складывает веса: .Записывает остатки последовательных делений в том порядке, в каком они получаются; читать их нужно от последнего к первому.Этот набор битов есть 26, удвоенное 13: биты сдвинуты на одну позицию.Каждая позиция весит вдвое больше соседней справа: единицы занимают позиции с весами 8, 4 и 1. Урок 3.4 работает непосредственно с этими битами, поэтому их полезно читать свободно.Повторить: Целые числа и их представление
Вопрос 3Из предыдущих разделовЧто выводит
std::println("{}", 0u - 1);при 32-битномunsigned int?Не учитывает суффиксu: у беззнакового типа нет отрицательных значений.Путает беззнаковую арифметику, определённую по модулю , со знаковым переполнением.Считает, что вычитание останавливается на наименьшем значении типа; на самом деле значение проходит круг.Беззнаковая арифметика ведётся по модулю : . Результат определён, и поэтому ни один санитайзер его не отмечает. Раздел снова встречает его в преобразованиях смешанного выражения и в битовых операторах, которые записываются с беззнаковыми типами.Повторить: Целые числа и их представление
Вопрос 4Из предыдущих разделовПрограмма выполняет
int count{std::numeric_limits<int>::max()};, а затемcount = count + 1;. Что гарантирует стандарт о значенииcount?Путает то, что иногда наблюдается, с тем, что гарантирует стандарт; переход к минимуму совершают беззнаковые, а не знаковые.Не учитывает предел типа: это число не помещается в 32-битныйint.Компилятор не знает значений, которые будут у программы во время выполнения; почти всегда он компилирует молча.У сложения есть предусловие, что результат помещается в тип, и вне его стандарт ничего не обещает. Санитайзер курса останавливает программу; без него может быть выведено что угодно. Урок 3.3 собирает этот случай вместе с другими того же рода в каталог.Повторить: Целые числа и их представление
Вопрос 5Чему равны и ?
Выполняет действия слева направо, не обращая внимания на приоритет произведения.Не замечает скобок во втором выражении.Приписывает каждому выражению значение другого: обращает действие скобок.Произведение связывает сильнее суммы: в сначала выполняется умножение, а скобки меняют этот порядок. C++ следует тому же соглашению, и урок 3.1 распространяет его на деление, остаток и ассоциативность, с деревом выражения в качестве инструмента.Повторить: Арифметические операции
Вопрос 6Чему равны, по теореме о делении из математики, где остаток подчинён условию , частное и остаток от деления на ?
Это то, что вычисляет C++, но условие не выполняется: математический остаток не бывает отрицательным.Не проверяет тождество: , а не .Тождество тоже не выполняется: .Теорема требует при , и эти два числа единственные, которые этому удовлетворяют. C++, напротив, округляет частное к нулю:-7 / 2равно , а-7 % 2равно . Урок 3.1 объясняет разницу и учит получать математический остаток из остатка C++.Повторить: Арифметические операции
Вопрос 7Каково отрицание высказывания «идёт дождь, и холодно»?
Отрицает каждую часть, не меняя связку: это утверждает гораздо больше, чем отрицание, потому что исключает и сухой холодный день.Отрицает только одну из частей.Говорит то же, что второй вариант, с той же ошибкой.Отрицание конъюнкции есть дизъюнкция отрицаний: это один из законов де Моргана. Чтобы утверждение стало ложным, достаточно, чтобы не выполнялось одно из двух. Урок 3.2 применяет тот же закон к условиям программы.Повторить: Отношения и логика
Вопрос 8Что выводит
std::println("{}", 3 < 5);?Считает, что логическое значение выводится числом; с заполнителем{}функцияstd::printlnвыводит слово.Считает, что выражение выводится как текст; выводится его значение.Является: сравнение есть выражение типаbool.Сравнение является выражением, как любое другое: у него есть значение типаbool, иstd::printlnвыводит его какtrueилиfalse. Урок 3.2 исходит из этого наблюдения: условие вычисляется, и поэтому у него есть приоритет, дерево и алгебра.Повторить: Отношения и логика
Вопрос 9Чему равны
aиbпослеint a{5};иint b{a++ * 2};?Это честный ответ: урок 3.3 учит различать значение выражения и его эффект, и итоговая проверка спросит об этом снова.Забывает об эффекте:a++увеличиваетa.Использует новое значениеa; постфиксный инкремент даёт прежнее значение.У выраженияa++есть значение, то, которое было уa(5), и эффект, который оставляет вaчисло 6. Произведение использует значение, а не эффект. Урок 3.3 учит различать эти две вещи и распознавать, когда два эффекта в одном выражении лишают его смысла.Повторить: Присваивание, побочные эффекты и неопределённое поведение
Вопрос 10Что выводит
std::println("{}", 2 ^ 3);?Это честный ответ: урок 3.4 это объясняет, и итоговая проверка спросит об этом снова.Читает «крышку» как степень, как в записи многих калькуляторов; в C++ это не так.Читает её как произведение.В C++ знак «крышка» обозначает не возведение в степень, а побитовое исключающее ИЛИ: и различаются только в бите с весом 1, так что результат равен 1. В C++ нет оператора возведения в степень; урок 3.4 учит, когда использоватьstd::pow, а когда сдвиг.Повторить: Биты и математическая библиотека
Загрузка содержимого…