Перейти к содержимому
Topos Uranos

Краткое содержание

Этот урок завершает второй раздел курса, посвящённый данным и их типам. Он восстанавливает цепочку понятий, ведущую от переменной к константе, за которой следит компилятор, через двоичное представление целых чисел и два их переполнения, приближённые вещественные числа и допуск, символы как коды и преобразования, теряющие информацию; отделяет то, что из этого верно для любого языка, от того, что присуще C++; собирает неопределённое поведение раздела, с тем, что обнаруживает компилятор, что обнаруживает санитайзер и чего не обнаруживает никто; повторяет в итоговой проверке навыки входной; и заканчивается шестью задачами повышенной трудности, объединяющими весь раздел.

Цели обучения

  1. Выбирать и обосновывать тип каждого данного задачи по значениям, которые оно может принимать, по требуемой точности и по операциям, которые с ним будут выполняться.
  2. Предсказывать последствия пределов представления в данной программе: переполнение целых чисел, округление чисел с плавающей точкой и потерю информации при преобразовании.
  3. Использовать именованные константы и явные преобразования и объяснять, что контролирует компилятор в каждом случае.
  4. Распознавать неопределённое поведение раздела и говорить для каждого случая, что его обнаруживает и как его предотвратить.
  5. Отделять в изученном за раздел то, что верно для любого языка, от того, что присуще C++.

Чего достиг раздел

Раздел ставил целью научить тому, что всякое данное живёт в памяти с типом, который определяет, какие значения оно может принимать, сколько места занимает и какие операции допускает, и что эти пределы имеют наблюдаемые последствия. Цель достигнута с опорой лишь на то, что введение объявило известным: рабочий цикл компиляции и запуска с параметрами курса, форматированный вывод, чтение через std::cin и чтение сообщений компилятора. Программу с четырьмя вычислениями, которой введение поставило задачу, теперь можно объяснить строка за строкой и исправить.

Переменные и память

Урок Переменные и память установил, что переменная есть ячейка памяти с именем, неизменным типом и меняющимся значением и что тип определяет её размер, который измеряет sizeof. Он отличил инициализацию от присваивания, показал, что фигурные скобки отвергают преобразование с потерей, и научил тому, что присваивание копирует, а не связывает, и что заменённое значение теряется; отсюда следует вспомогательная переменная при обмене значениями. Он определил состояние программы как совокупность значений её переменных и научил следить за ним с помощью таблицы трассировки. Он установил соглашения об именах и закончил первым неопределённым поведением раздела: чтением переменной, которая так и не получила значения.

Целые числа и их представление

Урок Целые числа и их представление научил позиционной системе счисления в основаниях 10, 2 и 16. Из того, что тип имеет nn бит, он вывел его диапазон значений: 2n2^n битовых комбинаций, которые без знака представляют числа от 00 до 2n−12^n - 1, а со знаком, в дополнительном коде, от −2n−1-2^{n-1} до 2n−1−12^{n-1} - 1, причём отрицательных на одно больше, чем положительных. Он различил два переполнения: переполнение беззнаковых целых, которое есть арифметика по модулю 2n2^n и определено (0u - 1 равно 4 294 967 2954\,294\,967\,295), и переполнение знаковых целых, которое есть неопределённое поведение и которое останавливает санитайзер. Он показал, что сравнение знакового целого с беззнаковым преобразует первое, так что сравнение −1<0u-1 < 0u ложно, и закончил критерием выбора целочисленного типа по предвидимому диапазону данного.

Числа с плавающей точкой

Урок Числа с плавающей точкой показал, что вещественное число хранится как знак, порядок и двоичная мантисса, так что представимые значения образуют конечное множество рациональных чисел со знаменателем, равным степени 2. Отсюда последовало, что числа 0.10.1 в машине нет: вместо него хранится ближайшее значение double, и 0.1 + 0.2 выводится как 0.30000000000000004. Урок оценил погрешность каждого округления, показал, что погрешности накапливаются и что сложение перестаёт быть ассоциативным; откуда вывел, что два вычисленных вещественных числа сравниваются не через ==, а по расстоянию между ними, с обоснованным допуском. Он закрепил double как вещественный тип по умолчанию и представил бесконечность и не-число, NaN.

Символы, логические значения, преобразования и константы

Урок Символы, логические значения, преобразования и константы показал, что тип есть правило чтения битов: char хранит байт, значение которого есть код ASCII символа, и поскольку цифры и буквы имеют последовательные коды, '7' - '0' равно 7; bool есть истина или ложь, и любое число, отличное от нуля, преобразуется в истину. Он изучил неявные преобразования и установил, что преобразование происходит внутри операции, по типу операндов, а не при сохранении результата: в double r{7 / 2} значение равно 3. Он научил записывать желаемое преобразование через static_cast, который не устраняет потерю, а объявляет её; уточнил, что фигурные скобки отвергают сужение, и показал третье неопределённое поведение раздела, преобразование в целое вещественного числа, которое не помещается. Он закончил константами (const, constexpr и static_assert), типом литералов и auto.