На этом уроке мы рассмотрим арифметические операторы и их использование в языке С++.
- Унарные арифметические операторы
- Бинарные арифметические операторы
- Деление целых чисел и чисел типа с плавающей точкой
- Использование оператора static_cast в операциях деления
- Деление с остатком
- Отрицательные числа в операциях деления до C++11
- Арифметические операторы присваивания
- Где оператор возведения в степень?
- Тест
Унарные арифметические операторы
Унарные операторы — это операторы, которые применяются только к одному операнду. Существуют два унарных арифметических оператора: плюс (+
) и минус (−
).
Оператор | Символ | Пример | Операция |
Унарный плюс | + | +x | Значение x |
Унарный минус | − | −x | Отрицательное значение x |
Унарный оператор +
возвращает значение операнда. Другими словами, +5 = 5
или +х = х
. Унарный плюс вам, скорее всего, не придется использовать. Его по большей части добавили в качестве симметрии с унарным оператором минус. Унарный оператор минус возвращает операнд, умноженный на −1
. Например, если х = 5
, то −х = −5
.
Оба этих оператора пишутся непосредственно перед самим операндом, без пробела (−x
, а не − x
).
Не следует путать унарный оператор минус с бинарным оператором вычитания, хоть они и используют один и тот же символ. Например, в выражении х = 5 − −3;
, первый минус — это оператор вычитания, а второй — унарный минус.
Бинарные арифметические операторы
Бинарные операторы — это операторы, которые применяются к двум операндам (слева и справа). Существует 5 бинарных операторов.
Оператор | Символ | Пример | Операция |
Сложение | + | x + y | x плюс y |
Вычитание | − | x − y | x минус y |
Умножение | * | x * y | x умножить на y |
Деление | / | x / y | x разделить на y |
Деление с остатком | % | x % y | Остаток от деления x на y |
Операторы сложения, вычитания и умножения работают так же, как и в обычной математике. А вот деление и деление с остатком рассмотрим детально.
Деление целых чисел и чисел типа с плавающей точкой
Оператор деления имеет два режима. Если оба операнда являются целыми числами, то оператор выполняет целочисленное деление. Т.е. любая дробь (больше/меньше) отбрасывается и возвращается целое значение без остатка, например, 7 / 4 = 1
.
Если один или оба операнда типа с плавающей точкой, то тогда будет выполняться деление типа с плавающей точкой. Здесь уже дробь присутствует. Например, выражения 7.0 / 3 = 2.333
, 7 / 3.0 = 2.333
или 7.0 / 3.0 = 2.333
имеют один и тот же результат.
Попытки деления на 0
(или на 0.0
) станут причиной сбоя в вашей программе, и это правило не следует забывать!
Использование оператора static_cast в операциях деления
На уроке о символьном типе данных char мы уже использовали оператор static_cast для вывода ASCII-символов в виде целых чисел.
Аналогичным образом мы можем использовать static_cast для конвертации целого числа в число типа с плавающей точкой. Таким образом, вместо целочисленного деления выполнится деление типа с плавающей точкой. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x = 7; int y = 4; std::cout << "int / int = " << x / y << "\n"; std::cout << "double / int = " << static_cast<double>(x) / y << "\n"; std::cout << "int / double = " << x / static_cast<double>(y) << "\n"; std::cout << "double / double = " << static_cast<double>(x) / static_cast<double>(y) << "\n"; return 0; } |
Результат выполнения программы:
int / int = 1
double / int = 1.75
int / double = 1.75
double / double = 1.75
Деление с остатком
Оператор деления с остатком (%
) работает только с целочисленными операндами и возвращает остаток от целочисленного деления. Например:
Пример №1: 7 / 4 = 1
с остатком 3
, таким образом, 7 % 4 = 3
.
Пример №2: 25 / 7 = 3
с остатком 4
, таким образом, 25 % 7 = 4
. Остаток составляет не дробь, а целое число.
Пример №3: 36 % 5 = 7
с остатком 1
. В числе 36 только 35 делится на 5 без остатка, поэтому 36 − 35 = 1
, 1
— это остаток и результат.
Данный оператор чаще всего используют для проверки деления без остатка одних чисел на другие. Если х % у == 0
, то х
делится на у
без остатка.
Например, мы хотим написать программу, которая выводит числа от 1 до 100 по 20 значений в каждой строке. Мы можем использовать оператор деления с остатком для создания разрыва строк. Несмотря на то, что мы еще не рассматривали цикл while, в следующей программе всё максимально просто и понятно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int main() { // Переменная count хранит текущее число для вывода int count = 1; // начинаем с 1 // Повторение операции (цикл) до тех пор, пока count не будет равен 100 while (count <= 100) { std::cout << count << " "; // вывод текущего числа // Если count делится на 20 без остатка, то вставляем разрыв строки и продолжаем с новой строки if (count % 20 == 0) std::cout << "\n"; count = count + 1; // переходим к следующему числу } // конец while return 0; } // конец main() |
Результат выполнения программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
О while мы еще поговорим на соответствующем уроке.
Отрицательные числа в операциях деления до C++11
До C++11, если любой из операндов целочисленного деления является отрицательным, то компилятор округляет результат самостоятельно! Например, результатом −5 / 2
может быть либо −3
, либо −2
. Однако большинство современных компиляторов округляют числа в сторону нуля (например, в −5 / 2
результатом будет −2
). В спецификации C++11 определили, что компилятор должен всегда округлять к нулю (или, проще говоря, просто отбрасывать дробь).
Также до C++11, если один из операндов оператора деления с остатком является отрицательным, то результат может быть как положительным, так и отрицательным! Например, результатом −5 % 2
может быть как 1
, так и −1
. В спецификации C++11 решили сделать так, чтобы результат a % b
был того же знака, что и значение а
.
Арифметические операторы присваивания
Оператор | Символ | Пример | Операция |
Присваивание | = | x = y | Присваиваем значение y переменной x |
Сложение с присваиванием | += | x += y | Добавляем y к x |
Вычитание с присваиванием | −= | x −= y | Вычитаем y из x |
Умножение с присваиванием | *= | x *= y | Умножаем x на y |
Деление с присваиванием | /= | x /= y | Делим x на y |
Деление с остатком и с присваиванием | %= | x %= y | Присваиваем остаток от деления x на y переменной x |
До этого момента, когда нам нужно было добавить число 5 к определенной переменной, мы делали следующее:
1 |
x = x + 5; |
Это работает, но требуется два оператора для выполнения.
Так как стейтменты типа х = х + 5
являются очень распространенными, то C++ предоставляет 5 арифметических операторов присваивания для нашего удобства. Вместо х = х + 5
, мы можем записать:
1 |
x += 5; |
Вместо:
1 |
x = x * y; |
Мы можем записать:
1 |
x *= y; |
Где оператор возведения в степень?
В языке C++ вместо оператора возведения в степень есть функция pow(), которая находится в заголовочном файле cmath. pow(base, exponent)
эквивалентно baseexponent
. Стоит отметить, что параметры pow() имеют тип double, поэтому вы можете использовать не только целые числа, но и дробные. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <cmath> // подключаем pow() int main() { std::cout << "Enter the base: "; double base; std::cin >> base; std::cout << "Enter the exponent: "; double exp; std::cin >> exp; std::cout << base << "^" << exp << " = " << pow(base, exp) << "\n"; return 0; } |
Тест
Задание №1
Вычислите результат следующего выражения: 6 + 5 * 4 % 3
.
Ответ №1
Поскольку операторы *
и %
имеют более высокий приоритет, чем оператор +
, то оператор +
будет выполняться последним. Мы можем переписать наше выражение следующим образом: 6 + (5 * 4 % 3)
. Операторы *
и %
имеют одинаковый приоритет, но их ассоциативность слева направо, так что левый оператор будет выполняться первым. Получается: 6 + ((5 * 4) % 3)
.
6 + ((5 * 4) % 3) = 6 + (20 % 3) = 6 + 2 = 8
Ответ: 8.
Задание №2
Напишите программу, которая просит пользователя ввести целое число, а затем сообщает, является ли его число чётным или нечётным. Напишите функцию isEven(), которая возвращает true
, если целое число является чётным. Используйте оператор деления с остатком, чтобы определить чётность числа.
Подсказка: Используйте ветвление if и оператор сравнения (==
).
Ответ №2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> bool isEven(int x) { // Если x % 2 == 0, то x - это чётное число return (x % 2) == 0; } int main() { std::cout << "Enter an integer: "; int x; std::cin >> x; if (isEven(x)) std::cout << x << " is even\n"; else std::cout << x << " is odd\n"; return 0; } |
Возможно, вы хотели написать или написали функцию isEven() следующим образом:
1 2 3 4 5 6 7 |
bool isEven(int x) { if ((x % 2) == 0) return true; else return false; } |
Хотя этот способ тоже рабочий, но он сложнее. Посмотрим, как его можно упростить. Во-первых, давайте вытащим условие if и присвоим его отдельной переменной типа bool:
1 2 3 4 5 6 7 8 |
bool isEven(int x) { bool isEven = (x % 2) == 0; if (isEven) // isEven - true return true; else // isEven - false return false; } |
В коде, приведенном выше, если переменная isEven
имеет значение true
, то возвращаем true
, в противном случае (если isEven
имеет значение false
) — возвращаем false
. Мы же можем сразу возвращать isEven
:
1 2 3 4 5 |
bool isEven(int x) { bool isEven = (x % 2) == 0; return isEven; } |
Так как переменная isEven
используется только один раз, то мы можем её вообще исключить:
1 2 3 4 |
bool isEven(int x) { return (x % 2) == 0; } |
Решил так.
Второе задание:
Можете, пожалуйста, пояснить как (count % == 0) отвечает за перенос следующей строки, а именно приравнивание к нулю
Просто проверяется каждое число, кратно ли оно двадцати. Если остаток от деления нулевой, значит число делится на двадцать нацело, а выражение (count % 20 == 0) справедливо. Ответ «Да» — и оператор пропускает нас к следующему действию, т.е. переносу строки std::cout << «\n»; «Нет» — и суда нет. Просто прибавляется счётчик, как будто никакого if не было. Возвращение к началу цикла, но уже с числом, большим на единицу. И так 100 раз, из которых имеем 5 случаев числа кратного 20 = 5 переносов строки.
Здравствуйте… очень нравится Ваш курс!
Такая запись приемлема или лучше как можно реже использовать тернарные операторы?
9 строк кода:
Для использования рекурсивных функций надо разбираться в памяти. 9 строк такого кода могут использовать больше памяти чем в другом решении. Плюс рекурсивная функция выполнятеся по времени дольше….
Получилось очень коротко, по сравнению с другими решениями. Программа работает, но правильно ли я сделал?
Крутое вступление)
Благодарю, Юрий! С детства любил читать книги по программированию… :-D. Читаю следующие главы и вижу, что в листинге можно кое-что оптимизировать (например, поменять i++ на ++i в циклах for…)
Добра и удачи!
Пожалуйста 🙂 И Вам добра и удачи!)
Заметил, что в листинге присутствует изменение типа значения функции <bool isEven(int number)> при передаче его в качестве аргумента функции <void printResult(int result)>… причём в самой функции <void printResult(int result)> происходит обратное преобразование в тип bool. Бывает… %-).
Задание №2:
Просто обожаю С++!!! Он мощный и красивый!
Я сделал проще
Оно проще, согласен. Но в задании требуется написать функция isEven().
Перепутал / с %.
Как-то так получилось
Вроде работает:
Решение задачи
"ifn.h"
main.cpp
Отошёл от пункта спецификации, где "Напишите функцию isEven(), которая возвращает true" и упростил программу 🙂
Моё решение на тест 2:
вот такой вот вариантчик
Все понял, каюсь и благодарю. Это ж целочисленный формат, епт… Незнаю чего так тупанул в таком простом моменте. Что поделать. Бывает.
Ничего страшного, это естественно в процессе изучения чего-либо. Главное — двигаться дальше)
Есть вопрос. В разделе "Отрицательные числа в операциях деления до C++11" есть такой фрагмент :
"… до C++11…результатом −5 % 2 может быть как 1, так и −1…"
Но как??? Может как 5 так и -5? Откуда там еденица?
Прежде чем писать комментарий вы бы перечитали весь материал лучше… Деление с остатком не есть деление: 7%4=3; 6%4=2; 5%4=1; 4%4=0.
Ну правильно все пишете. А 5/2 сколько будет? Правильно, 2.5. Какой остаток дробный видим? Правильно, 0.5. Так что должно быть результатом выражения 5%2 по вышеприведенной вами же логике? Не 5, нет? Откуда 1?
Владимир, перечитайте урок ещё раз и посмотрите информацию в Интернете по поводу оператора % (остаток от деления). 5%2=1 от того, что 2*2=4 и 5-4=1.
Спешу вас удивить владимир, но
5 / 2 = 2! а уже 5.0 / 2 или 5 / 2.0 или 5.0 / 2.0 вот тогда ровняется 2.5. Ибо int / int = int! И советую я вам перечитать внимательно не только это урок но и главу 2 (в частности уроки 31, 32, и 33). Да и привыкайте разбираться сами, ибо путь этот тернист подводными камнями 😉
Владимир, кто вам сказал, что остаток от деления — это то что после десятичной точки? Тут и есть ваша ошибка.
Я написал без применения функции. Но с проблемой — компьютер отвечает с запозданием. Писалось в Eclipse IDE, Manjaro Linux.
Даже не знаю как я мог не понять эти деления, но было ясно насчет if.
Буль можно использовать, но как поставил Ваш вариант — подумал, зачем.
Не знаю кому проще или сложнее, но вроде бы проще уже некуда.
Неудобно только то, что у вас многие стейтменты в одну строчку.
Вот мой вариант. Юрий посмотрите и скажите свое мнение.
По примеру задачки из итогового теста (если точней, то по примеру вашего решения) — сделал вот так.
Попробовал — работает.
Посмотрел ваше решение тут — узнал опять много нового 🙂
Например то, что при инициализации переменной можно делать вот так
(почему-то не подумал бы, что проверка == будет работать при инициализации тоже).
А вот то, что return может и сам посчитать — уже знал, но забыл 🙁 Так бы сразу через него и сделал, но получилось вообще через if о_О
Кстати по прошлым примерам, когда мы все действия запихивали каждое в свою ф-цию, сделал всю программу на сколько смог. Пытался и последний if впихнуть, но с ним что-то не захотело… 🙂 Только вот может в больших программах это и имеет смысл, но вот в таких — кажется излишне громоздким и не нужным. Ваш пример здесь намного удобней и красивей смотрится.
Кстати вопрос.
Задачки — тоже с источника, или сами делаете?)
Решил сделать вот так, надеюсь, что правильно.
немного упростил IsEven
Андрюха, ты лучший!
У меня вопрос, а зачем вот так расписывать, когда , если нам нужно вывести просто результат ?
Если только для подачи материала ? если так — то гуд.
Согласен. Но:
please ENTRE number
Эммм… вы француз? ))
(Я знаю, что E и R находятся рядом, но это смешно)
Думаю это ,не плохое решение.
Плохое. Одна функция должна выполнять одну задачу. У вас все задачи выполняет одна функция.
И красивее будет, если setlocale(LC_ALL, "ru"); Без нее сейчас как без рук. Для понимания лучше.
И вот вопрос: при вводе 5, сообщается о нечетности. А при вводе 5.5… тоже сообщается о нечетности)))) почему? Переменная int.
Потому что любая дробь отбрасывается, а не округляется. Будь у вас 5.99 — эта дробь отбросится и останется 5.
А еще функция должна возвращать значение bool, а возвращает int.
Это не проблема, на самом деле, тут вообще не было разницы, какой тип функции. Её можно было сделать void, и просто выполнить. Но меня заинтересовало, что она выводит в cout, если на возврат ставится введённое пользователем число. Вполне ожидаемо, что ненулевое значение трансформировалось в логическую единицу. Так что сюрпризу спасибо за интересный эксперимент.
Я так сделал
Хорошее решение, действительно.
У меня похожий вариант:
Не понимаю, зачем использовать с bool. По мне, это усложняет код.
Сетлокейл не забываем ))
Суть тестового задания не только в том что бы программа работала, скорее так: смыслом условий написания программ из тестов есть целенаправленное закрепления пройденного материала. То есть код хорош тогда, когда он удовлетворяет заданные условия из теста и в нем не нарушаются рекомендации указанные ранее.
Именно!
Усложнение простого кода поможет в будущем упростить сложный код. Парадоксально немного, но так оно и работает. Тяжело в учении — легко в бою)
так можно же?)
Да, можно и так. Как вариант.
Возвращение к единице обратно
А как быть с нечетными 1 и-1?
Так ведь программа правильно работает. 1 и -1 — нечетные числа.