4.2. Арифметические операторы

Таблица 4.1. Арифметические операторы

(левосторонний порядок)

Оператор Действие Применение + Унарный плюс + выражение - Унарный минус - выражение * Умножение выражение * выражение / Деление выражение / выражение % Остаток выражение % выражение + Сложение выражение + выражение - Вычитание выражение - выражение

В табл. 4.1 (и таблицах операторов последующих разделов) операторы сгруппированы по приоритету. Унарные арифметические операторы имеют более высокий приоритет, чем операторы умножения и деления, которые в свою очередь имеют более высокий приоритет, чем парные операторы вычитания и сложения. Операторы с более высоким приоритетом группируются перед операторами с более низким приоритетом. Все эти операторы имеют левосторонний порядок, т.е. при равенстве приоритетов они группируются слева направо.

Если не указано иное, то арифметические операторы могут быть применены к любому арифметическому типу (см. раздел 2.1.1) или любому типу, который может быть преобразован в арифметический тип. Операнды и результаты этих операторов являются r-значениями. Как упоминается в разделе 4.11, в ходе вычисления операторов их операнды малых целочисленных типов преобразуются в больший целочисленный тип и все операнды могут быть преобразованы в общий тип.

Унарные операторы плюс и минус могут быть также применены к указателям. Использование парных операторов + и - с указателями рассматривалось в разделе 3.5.3. Будучи примененным к указателю или арифметическому значению, унарный плюс возвращает (возможно, преобразованную) копию значения своего операнда.

Унарный оператор минус возвращает отрицательную копию (возможно, преобразованную) значения своего операнда.

int i = 1024;

int k = -i;   // i равно -1024

bool b = true;

bool b2 = -b; // b2 равно true!

В разделе 2.1.1 упоминалось, что значения типа bool не нужно использовать для вычислений. Результат -b — хороший пример того, что имелось в виду.

Для большинства операторов операнды типа bool преобразуются в тип int. В данном случае значение переменной b, true, преобразуется в значение 1 типа int (см. раздел 2.1.2). Это (преобразованное) значение преобразуется в отрицательное, -1. Значение -1 преобразуется обратно в тип bool и используется для инициализации переменной b2. Поскольку значение инициализатора отлично от нуля, при преобразовании в тип bool его значением станет true. Таким образом, значением b2 будет true!

Внимание! Переполнение переменной и другие арифметические особенности

Некоторые арифметические выражения возвращают неопределенный результат. Некоторые из этих неопределенностей имеют математический характер, например деление на нуль. Причиной других являются особенности компьютеров, например, переполнение, происходящее при превышении вычисленным значением размера области памяти, представленной его типом.

Предположим, тип short занимает на машине 16 битов. В этом случае переменная типа short способна хранить максимум значение 32767. На такой машине следующий составной оператор присвоения приводит к переполнению.

short short_value = 32767; // максимальное значение при short 16 битов

short_value += 1;          // переполнение

cout << "short_value: " << short_value << endl;

Результат присвоения 1 переменной short_value непредсказуем. Для хранения знакового значения 32768 требуется 17 битов, но доступно только 16. Многие системы никак не предупреждают о переполнении ни во время выполнения, ни во время компиляции. Подобно любой ситуации с неопределенностью, результат оказывается непредсказуем. На системе авторов программа завершилась с таким сообщением:

short value: -32768

Здесь произошло переполнение переменной: предназначенный для знака разряд содержал значение 0, но был заменен на 1, что привело к появлению отрицательного значения. На другой системе результат мог бы быть иным, либо программа могла бы повести себя по-другому, включая полный отказ.

Примененные к объектам арифметических типов, операторы +, -, * и / имеют вполне очевидные значения: сложение, вычитание, умножение и деление. Результатом деления целых чисел является целое число. Получаемая в результате деления дробная часть отбрасывается.

int ival1 = 21/6; // ival1 равно 3; результат усекается

                  // остаток отбрасывается

int ival2 = 21/7; // ival2 равно 3; остатка нет;

                  // результат - целочисленное значение

Оператор % известен как остаток (remainder), или оператор деления по модулю (modulus). Он позволяет вычислить остаток от деления левого операнда на правый. Его операнды должны иметь целочисленный тип.

int ival = 42;

double dval = 3.14;

ival % 12;   // ok: возвращает 6

ival % dval; // ошибка: операнд с плавающей запятой

При делении отличное от нуля частное позитивно, если у операндов одинаковый знак, и отрицательное в противном случае. Прежние версии языка разрешали округление отрицательного частного вверх или вниз; однако новый стандарт требует округления частного до нуля (т.е. усечения).

Оператор деления по модулю определен так, что если m и n целые числа и n отлично от нуля, то (m/n)*n + m%n равно m. По определению, если m%n отлично от нуля, то у него тот же знак, что и у m. Прежние версии языка разрешали результату выражения m%n иметь тот же знак, что и у m, причем на реализациях, у которых отрицательный результат выражения m/n округлялся не до нуля, но такие реализации сейчас запрещены. Кроме того, за исключением сложного случая, где -m приводит к переполнению, (-m)/n и m/(-n) всегда эквивалентны -(m/n), m%(-n) эквивалентно m%n и (-m)%n эквивалентно -(m%n). А конкретно:

 21 % 6;  /* результат 3  */  21 / 6;  /* результат 3  */

 21 % 7;  /* результат 0  */  21 / 7;  /* результат 3  */

-21 % -8; /* результат -5 */ -21 / -8; /* результат 2  */

 21 % -5; /* результат 1  */  21 / -5; /* результат -4 */

Упражнения раздела 4.2

Упражнение 4.4. Расставьте скобки в следующем выражении так, чтобы продемонстрировать порядок его обработки. Проверьте свой ответ, откомпилировав и отобразив результат выражения без круглых скобок.

12 / 3 * 4 + 5 * 15 + 24 % 4 / 2

Упражнение 4.5. Определите результат следующих выражений:

(а) -30 * 3 + 21 / 5 (b) -30 + 3 * 21 / 5

(с) 30 / 3 * 21 % 5  (d) -30 / 3 * 21 % 4

Упражнение 4.6. Напишите выражение, чтобы определить, является ли значение типа int четным или нечетным.

Упражнение 4.7. Что значит переполнение? Представьте три выражения, приводящих к переполнению.

Более 800 000 книг и аудиокниг! 📚

Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением

ПОЛУЧИТЬ ПОДАРОК