Целочисленная арифметика¶
Специальный символ, выполняющий арифметические вычисления. В выражении a * b символ * — оператор умножения, a и b — его операнды.
Оператор, принимающий два операнда, называется бинарным. Унарный оператор принимает один операнд. Пример унарного оператора: -1 .
Последовательность операторов и операндов, результат вычисления которой сводится к единственному значению. Простейшие выражения состоят из одного значения и не содержат операторов: 42 , "Hello, World!" . Пример более сложного выражения: 2 ** 32 — 1 .
Свойство оператора, влияющее на очередность его выполнения в выражении с несколькими различными операторами при отсутствии явного (с помощью скобок) указания на порядок их вычисления.
Например, результат выражения 2 + 2 * 2 — 6, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Изменить порядок вычислений в выражении можно с помощью скобок:
последовательность выполнения операций (или направление вычисления), реализуемая когда операции имеют одинаковый приоритет и отсутствует явное (с помощью скобок) указание на очерёдность их выполнения.
Различают правую (справа налево) и левую (слева направо) ассоциативность. Пример оператора с левой ассоциативностью — оператор деления / . Так, выражение 8 // 4 // 2 эквивалентно (8 // 4) // 2 и его результат равен 1.
Пример оператора с правой ассоциативностью — оператор возведения в степень:
Арифметические операторы¶
В таблице приведены некоторые арифметические операторы языка Python в порядке уменьшения приоритета (операторы с наибольшим приоритетом расположены выше).
Возведение в степень
Унарные плюс и минус
Сложение и вычитание
Целочисленное деление и взятие остатка от деления¶
Рассмотрим выражение \(7 / 2\) . Частное можно записать в виде десятичной дроби: \(3.5\) . Однако в ряде задач нам нужны отдельно целая часть и остаток от деления. Очевино, целая часть результата равна \(3\) . Тогда для вычисления остатка от \(7\) нужно отнять произведение целой части на делимое, т.е. остаток равен \(7 — 3 \cdot 2\) .
Такие операции поддерживаются в Python напрямую. Так, для целочисленного деления используется оператор // , а для получения остатка от деления оператор % :
Эти операции полезны при вычислениях с отдельными разрядами чисел.
Пусть дано число \(8192\) , и нам необходимо получить его третий разряд, т.е. единицу. \(8192 // 10^2 \% 10 = 8192 // 100 \% 10 = 81 \% 10 = 1\) .
Функции перевода чисел в различные системы счисления¶
Функции принимают целое число и возвращают его строковое представление в двоичной, восьмеричной и шестнадцатеричной системах счисления соответственно.
С этой функцией мы познакомились на прошлом занятии. Сейчас дополним, что вторым аргументом она может принимать основание системы счисления, в которой записано число x :
Задачи¶
Дано целое десятичное число. Выведите его последнюю цифру.
Дано целое десятичное число. Найдите число десятков в его десятичной записи.
Дано трехзначное число. Найдите сумму его цифр.
Пирожок в столовой стоит \(a\) рублей и \(b\) копеек. Определите, сколько рублей и копеек нужно заплатить за \(n\) пирожков.
Приложение запрашивает у пользователя стоимость одного пирожка и количество пирожков. Пример:
Приложение должно вычислить стоимость запрошенного количества пирожков. Пример вывода:
Дано число \(n\) . С начала суток прошло n минут. Определите, сколько часов и минут будут показывать электронные часы в этот момент. Программа должна вывести два числа: количество часов (от 0 до 23) и количество минут (от 0 до 59). Учтите, что число \(n\) может быть больше, чем количество минут в сутках.
Дополнительные задачи¶
В школе решили набрать три новых математических класса. Так как занятия по математике у них проходят в одно и то же время, было решено выделить кабинет для каждого класса и купить в них новые парты. За каждой партой может сидеть не больше двух учеников. Известно количество учащихся в каждом из трёх классов. Сколько всего нужно закупить парт чтобы их хватило на всех учеников? Программа получает на вход три целых десятичных числа: количество учащихся в каждом из трех классов.
Обувная фабрика собирается начать выпуск элитной модели ботинок. Дырочки для шнуровки будут расположены в два ряда, расстояние между рядами равно \(a\) , а расстояние между дырочками в ряду \(b\) . Количество дырочек в каждом ряду равно \(N\) . Шнуровка должна происходить элитным способом «наверх, по горизонтали в другой ряд, наверх, по горизонтали и т.д.» (см. рисунок). Кроме того, чтобы шнурки можно было завязать элитным бантиком, длина свободного конца шнурка должна быть \(l\) . Какова должна быть длина шнурка для этих ботинок?
Программа получает на вход четыре натуральных числа \(a\) , \(b\) , \(l\) и \(N\) и должна вывести одно число — искомую длину шнурка.
3. Занятия в школе начинаются в 9:00. Продолжительность урока — 45 минут, перемены — 10 минут. На вход принимается номер урока, а выводится время, в которое он заканчивается (часы и минуты отдельно). Пример вывода:
4. Доработайте код задачи № 3 таким образом, чтобы он запрашивал время начала занятий (минуты и часы отдельно) и номер урока, а далее также рассчитывал время окончания уроков.
5. Пользователь вводит число и систему счисления этого числа. Программа переводит число в десятичную, двоичную, восьмеричную и шестнадцетеричную системы счисления с использованием стандартных функций. Пример вывода:
Домашнее задание¶
Дано трехзначное число. Найти произведение его цифр.
Даны значения двух моментов времени, принадлежащих одним и тем же суткам: часы, минуты и секунды для каждого из моментов времени. Известно, что второй момент времени наступил не раньше первого. Определите, сколько секунд прошло между двумя моментами времени.
Целочисленная арифметика. Делим с округлением результата. Часть 1
Чем проще, на первый взгляд, задача, тем меньше разработчик вдумывается в то, как грамотно её реализовать, и допущенную ошибку, в лучшем случае, обнаруживает поздно, в худшем — не замечает вовсе. Речь пойдет об одной из таких задач, а именно, о дробном делении и о масштабировании в контроллерах, поддерживающих исключительно целочисленную арифметику.
Почему тонкостям вычислений в условиях такой арифметики разработчики прикладных программ не уделяют внимание, вопрос. Рискну только предположить, что, по всей вероятности, сказывается привычка производить вычисления на калькуляторе… Во всяком случае, с завидной регулярностью «имею счастье» лицезреть, как коллеги по цеху наступают на одни и те же грабли. Этот материал нацелен на то, чтобы те самые «грабли» нейтрализовать.
При целочисленной арифметике результат деления одного целого числа на другое состоит из двух чисел — частного и остатка. Если остаток деления отбросить, получим результат, в абсолютной величине округленный до меньшего целого.
Реализуя вычисления с дробями, этот момент частенько упускают из вида, а, упустив, получают потери в точности вычислений. Причем точность вычислений падает с ростом величины делителя. К примеру, что 53/13, что 64/13 дадут в результате 4, хотя, по факту, частное от деления второй дроби существенно ближе к 5.
Принимая во внимание то, что такие вычисления в программе могут потребоваться неоднократно, алгоритм вычислений реализуем в формате, пригодном для упаковки в подпрограмму.
Для корректного выполнения необходимых для этого промежуточных вычислений понадобится массив из пяти регистров, обозначим его условно TEMP[0..4]. Почему пять и не меньше, поясню чуть ниже.
Шаги с 3-го по 7-й могут быть вынесены в подпрограмму.
При желании, запись результата может быть произведена непосредственно суммированием TEMP[0] c TEMP[1] за пределами подпрограммы расчета. Это непринципиально. Единственное, следует иметь в виду, что при множестве однотипных расчетов вынос операции сложения в основное тело программы способен привести к возрастанию задействованного ею объема программной памяти.
Так почему же для промежуточных вычислений потребовалось целых 5 регистров? А операция суммирования остатка деления самого с собой, о чем говорилось ранее, заменена умножением остатка на два? Очень просто — для того, чтобы оперировать с неограниченным набором целых чисел.
Поясню: если поделить, к примеру, число 32767 на -32768 в остатке получим 32767, и результат его сложения несомненно выйдет за пределы диапазона integer.
5.2 – Арифметические операторы
В C++ есть два унарных арифметических оператора, плюс (+) и минус (-). Напоминаем, что унарные операторы – это операторы, которые принимают только один операнд.
Оператор | Обозначение | Пример использования | Операция |
---|---|---|---|
Унарный плюс | + | +x | Значение x |
Унарный минус | — | -x | Отрицательное значение x |
Оператор унарного минуса возвращает операнд, умноженный на -1 . Другими словами, если x = 5 , -x равно -5 .
Оператор унарного плюса возвращает значение операнда. Другими словами, +5 равно 5 , а +x равно x . Как правило, вам не нужно использовать этот оператор, поскольку он избыточен. Он был добавлен в основном для обеспечения симметрии с унарным оператором минус.
Для наилучшего эффекта оба этих оператора следует размещать непосредственно перед операндом (например, -x , а не — x ).
Не путайте оператор унарного минуса с оператором бинарного вычитания, в котором используется тот же символ. Например, в выражении x = 5 — -3; первый минус – это оператор бинарного вычитания, а второй – оператор унарного минуса.
Бинарные арифметические операторы
В C++ есть 5 бинарных арифметических операторов. Бинарные операторы – это операторы, которые принимают левый и правый операнды.
Оператор | Обозначение | Пример использования | Операция |
---|---|---|---|
Сложение | + | x + y | x плюс y |
Вычитание | — | x — y | x минус y |
Умножение | * | x * y | x , умноженное на y |
Деление | / | x / y | x , деленное на y |
Остаток от деления | % | x % y | остаток от деления x на y |
Операторы сложения, вычитания и умножения работают так же, как и в реальной жизни, без каких-либо оговорок.
Деление и остаток от деления требуют дополнительных пояснений. О делении мы поговорим ниже, а об остатке от деления – в следующем уроке.
Целочисленное деление и деление с плавающей запятой
Проще всего представить себе, что оператор деления имеет два разных «режима».
Если один (или оба) операнда являются значениями с плавающей точкой, оператор деления выполняет деление с плавающей точкой. Деление с плавающей точкой возвращает значение с плавающей точкой, и дробная часть сохраняется. Например, 7.0 / 4 = 1.75 , 7 / 4.0 = 1.75 и 7.0 / 4.0 = 1.75 . Как и во всех арифметических операциях с плавающей точкой, здесь могут возникать ошибки округления.
Если оба операнда являются целыми числами, оператор деления вместо этого выполняет целочисленное деление. Целочисленное деление отбрасывает любые дробные части и возвращает целочисленное значение. Например, 7 / 4 = 1 , потому что дробная часть результата отбрасывается. Точно так же -7 / 4 = -1 , потому что дробная часть опускается.
Предупреждение
До C++11 целочисленное деление с отрицательным операндом могло округляться в большую или меньшую сторону. Таким образом, -5 / 3 могло дать результат -1 или -2 . Это было исправлено в C++11, где дробная часть всегда отбрасывается (округляется до 0).
Использование static_cast<> для деления с плавающей точкой с целочисленными значениями
Сказанное выше поднимает вопрос: если у нас есть два целых числа и мы хотим разделить их без потери дробной части, как нам это сделать?
В уроке «4.11 – Символы» мы показали, как можно использовать оператор static_cast<> для преобразования значения char в целочисленный тип, чтобы оно печаталось как целое число, а не как символ.
Аналогичным образом мы можем использовать static_cast<> для преобразования значения целочисленного типа в число с плавающей точкой, чтобы мы, вместо целочисленного деления, смогли выполнить деление с плавающей точкой. Рассмотрим следующий код:
Приведенный выше пример показывает, что если любой из операндов является числом с плавающей точкой, результатом будет деление с плавающей точкой, а не целочисленное деление.
Деление на ноль
Попытка разделить на 0 (или 0.0) обычно приводит к сбою программы, так как результаты математически не определены!
Это работает, но немного неудобно и требует для выполнения двух операторов ( operator+ и operator= ).
Поскольку написание таких инструкций, как x = x + 4 , очень распространено, C++ для удобства предоставляет пять арифметических операторов присваивания. Вместо того, чтобы писать x = x + 4 , вы можете написать x += 4 . Вместо x = x * y вы можете написать x *= y .
Операции отношения или сравнения
П
Операция целочисленного деления и операция — остаток от деления
Остановимся немного подробнее на операции целочисленного деления (div) и операции, выдающей остаток от деления (mod).
Так, результатом целочисленного деления 17 на 5 будет 3:
17 div 5 = 3, а результатом деления меньшего числа на большее, будет 0:
Делаем вывод, что при целочисленном деление дробная часть отбрасывается, сам термин «целочисленное деление» или «деление нацело» говорит сам за себя.
Операция a div b осуществляет целочисленное деление целого a на целое b.
Дробная часть при этом отбрасывается.
Еще одна интересная операция — остаток от деления a на b.
Понятно, что остатком от деления 17 на 5 будет число 2:
а вот чему будет равен остаток от деления меньшего числа на большее, например, 46 mod 200?
Оказывается, в этом случае, результатом операции будет число 46. Вот другие примеры:
Интересно, что остаток от деления любого целого числа на 10 будет равен последней цифре этого числа:
543 mod 10 = 3, 45 mod 10 = 5, 7 mod 10 = 7.
Константа в программе на Паскале — это идентификатор, являющийся обозначением конкретного числа, которое называется значением константы; отличие же константы от переменной в том, что ее значение нельзя изменять с помощью операторов программы, а также в том, что значение константы закрепляется в ней еще до выполнения операторов, в разделе описаний.
Каждая константа должна быть описана в программе. Примеры описания:
Такого рода описание может охватывать и несколько констант.
Const n = 100; m = 25; k = 1000;
Константы такого вида называются нетипизированными. Существуют константы, в описании которых кроме значения есть тип, например:
Const m: integer = 25;
Такие константы являются типизированными и их значения можно изменять с помощью операторов программы. Типизированные константы отличаются от переменных только тем, что описываются после ключевого слова Const и их значения указываются в разделе описаний.
Кроме арифметических операций, в Паскале существуют так называемые стандартные или встроенные функции, которые выполняются сразу после указания их имени, заведомо объявленных в Паскале, после которого в скобках записывается аргумент функции.