4.2. Arithmetic Operators
Table 4.1 (and the operator tables in subsequent sections) groups the operators by their precedence. The unary arithmetic operators have higher precedence than the multiplication and division operators, which in turn have higher precedence than the binary addition and subtraction operators. Operators of higher precedence group more tightly than do operators with lower precedence. These operators are all left associative, meaning that they group left to right when the precedence levels are the same.
Table 4.1. Arithmetic Operators (Left Associative)
Operator | Function | Use |
---|---|---|
+ | Unary plus | +expr |
- | Unary minus | -expr |
+ | Addition | expr + expr |
- | Subtraction | expr - expr |
* | Multiplication | expr * expr |
/ | Division | expr / expr |
% | Remainder | expr % expr |
Unless noted otherwise, the arithmetic operators may be applied to any of the arithmetic types (§ 2.1.1, p. 32) or to any type that can be converted to an arithmetic type. The operands and results of these operators are rvalues. As described in § 4.11 (p. 159), operands of small integral types are promoted to a larger integral type, and all operands may be converted to a common type as part of evaluating these operators.
The unary plus operator and the addition and subtraction operators may also be applied to pointers. § 3.5.3 (p. 119) covered the use of binary +
and -
with pointer operands. When applied to a pointer or arithmetic value, unary plus returns a (possibly promoted) copy of the value of its operand.
The unary minus operator returns the result of negating a (possibly promoted) copy of the value of its operand:
int i = 1024;
int k = -i; // i is -1024
bool b = true;
bool b2 = -b; // b2 is true!
In § 2.1.1 (p. 34) we noted that bool
values should not be used for computation. The result of -b
is a good example of what we had in mind.
For most operators, operands of type bool
are promoted to int
. In this case, the value of b
is true
, which promotes to the int
value 1
(§ 2.1.2, p. 35). That (promoted) value is negated, yielding -1
. The value -1
is converted back to bool
and used to initialize b2
. This initializer is a nonzero value, which when converted to bool
is true
. Thus, the value of b2
is true
!
INFO
Caution: Overflow and Other Arithmetic Exceptions
Some arithmetic expressions yield undefined results. Some of these undefined expressions are due to the nature of mathematics—for example, division by zero. Others are undefined due to the nature of computers—for example, due to overflow. Overflow happens when a value is computed that is outside the range of values that the type can represent.
Consider a machine on which short
s are 16 bits. In that case, the maximum short
is 32767. On such a machine, the following compound assignment overflows:
short short_value = 32767; // max value if shorts are 16 bits
short_value += 1; // this calculation overflows
cout << "short_value: " << short_value << endl;
The assignment to short_value
is undefined. Representing a signed value of 32768 requires 17 bits, but only 16 are available. On many systems, there is no compile-time or run-time warning when an overflow occurs. As with any undefined behavior, what happens is unpredictable. On our system the program completes and writes
short_value: -32768
The value “wrapped around”: The sign bit, which had been 0, was set to 1, resulting in a negative value. On another system, the result might be different, or the program might behave differently, including crashing entirely.
When applied to objects of arithmetic types, the arithmetic operators, +
, -
, *
, and /
, have their obvious meanings: addition, subtraction, multiplication, and division. Division between integers returns an integer. If the quotient contains a fractional part, it is truncated toward zero:
int ival1 = 21/6; // ival1 is 3; result is truncated; remainder is discarded
int ival2 = 21/7; // ival2 is 3; no remainder; result is an integral value
The %
operator, known as the “remainder” or the “modulus” operator, computes the remainder that results from dividing the left-hand operand by the right-hand operand. The operands to %
must have integral type:
int ival = 42;
double dval = 3.14;
ival % 12; // ok: result is 6
ival % dval; // error: floating-point operand
In a division, a nonzero quotient is positive if the operands have the same sign and negative otherwise. Earlier versions of the language permitted a negative quotient to be rounded up or down; the new standard requires the quotient to be rounded toward zero (i.e., truncated).
C++11The modulus operator is defined so that if m
and n
are integers and n
is nonzero, then (m/n)*n + m%n
is equal to m
. By implication, if m%n
is nonzero, it has the same sign as m
. Earlier versions of the language permitted m%n
to have the same sign as n
on implementations in which negative m/n
was rounded away from zero, but such implementations are now prohibited. Moreover, except for the obscure case where -m
overflows, (-m)/n
and m/(-n)
are always equal to -(m/n)
, m%(-n)
is equal to m%n
, and (-m)%n
is equal to -(m%n)
. More concretely:
21 % 6; /* result is 3 */ 21 / 6; /* result is 3 */
21 % 7; /* result is 0 */ 21 / 7; /* result is 3 */
-21 % -8; /* result is -5 */ -21 / -8; /* result is 2 */
21 % -5; /* result is 1 */ 21 / -5; /* result is -4 */
INFO
Exercises Section 4.2
Exercise 4.4: Parenthesize the following expression to show how it is evaluated. Test your answer by compiling the expression (without parentheses) and printing its result.
12 / 3 * 4 + 5 * 15 + 24 % 4 / 2
Exercise 4.5: Determine the result of the following expressions.
(a)-30 * 3 + 21 / 5
(b)-30 + 3 * 21 / 5
(c)30 / 3 * 21 % 5
(d)-30 / 3 * 21 % 4
Exercise 4.6: Write an expression to determine whether an int
value is even or odd.
Exercise 4.7: What does overflow mean? Show three expressions that will overflow.