Every algorithm of any consequence makes extensive use of arithmetic operators, whether it is executed by hand or realized as a computer program and executed by a computer. However, the two are different in one very important way. Calculations that are performed by hand tend to progress down the page, using more and more memory (i.e., paper) as they proceed. Programs, on the other hand, tend to declare a small number of variables, assign values to them, and then assign updated values to them. This chapter considers different ways of updating variables.
Suppose you are writing a program that keeps track of the age of your favorite relative. You might declare an
int variable named
age and assign your favorite relative’s current age to that variable.
Now, suppose you need to perform a calculation involving that relative’s age next year. Obviously, you know that their age will be one greater than it is now. But, should you create another variable for that value, or should you just update the value of
age? In some situations you need to do the former, but, suppose what you need to do is update the existing variable. It turns out that there are a variety of different ways that you can proceed.
One approach to updating that you may have already seen involves the increment and decrement operators,
-, which increase/decrease their operands by one. So, for example, you have probably seen something like the following:
int age; // Initialize the age to 0 at birth age = 0; // Increase the age by 1 on the first birthday age++;
What you may not know is that, in some ways, this is just one (particularly simple) way of solving a specific updating problem (i.e., in which the variable is increased or decreased by exactly 1).
Thinking About The Problem
The same result can be achieved in a slightly more complicated but, ultimately, more flexible way. To understand how, first remember that the assignment operator takes the result of evaluating the expression on its right and puts it in the memory location identified by the variable on its left. This is done three different times in the following example:
int currentAge, increment, initialAge; initialAge = 0; increment = 1; currentAge = initialAge + increment;
These three assignment statements are particularly easy to understand because the expression on the right side of the assignment operator does not involve the variable on the left side. However nothing about the syntax of assignment statements prevents this from being the case. For example, consider the following statement:
// Add age and 1 and assign the result to age age = age + 1;
This statement first adds the value in the memory location identified by
age and the value
1 and then assigns the result to the memory location identified by
age. In other words, it does the same thing as
To the non-programmer this statement looks like a mistake because the non-programmer thinks that it says “
age plus one”, which clearly can’t be true. However, that’s not what it says at all. It actually says “add the value in the memory location identified by
age and the value one, and put the result in the memory location identified by
This idea can be generalized in a variety of ways by recognizing that the important pattern is the presence of the left-side operand on the right side of the assignment operator. In a fairly abstract way, the pattern can be written (in pseudo-code) as follows:
value = value operator adjustment
value denotes the variable being updated,
= denotes the assignment operator,
operator denotes a binary operator, and
adjustment represents the “amount” of the adjustment. Since
operator has higher precedence than
=, it is evaluated first. Then, the result of that evaluation (which involves
value) is assigned to
This pattern is so common, that experienced programmers neither think about it themselves nor think to mention it to beginning programmers, but it’s not as obvious as everyone makes it out to be.
You will encounter many situations in which you must keep track of something that is changing, but, regardless of its value, you want to use the same name/identifier. In the example above, you needed to keep track of a relative’s age over time, but you only needed their current age. In another program you may need to keep track of someone’s bank balance as it changes over time, but you only need the current balance. In still another program, you may need to keep track of the elevation of a highway as it changes over space, but you only need the elevation at one location.
A Gradebook Program
Suppose you have to write a program that manages the grades that a student receives in a course. After the initial grade is assigned, you must deduct the late penalty (which may, of course, be zero). You can implement this as follows:
// Assign the initial grade grade = 85; // Reduce a grade by a late penalty grade = grade - latePenalty;
A Retail Sales Program
Now, suppose you have to write a program that offers frequent buyers a 25% discount when they check out. You could solve this problem as follows:
// Offer a 25% discount price = price - 0.25*price;
* operator has the highest precedence, it is evaluated first. Then, the result of the multiplication operation is subtracted from the
price (without changing the contents of any of the variables). Finally, the result of the subtraction operation is assigned to the variable named
price initially contains the value
40.0. Then, this statement can be visualized as in Figure 1.1.
A Banking Program
As one more example, suppose you have to write a program that updates an account holder’s bank balance. Assuming an interest rate of 5%, the new balance will equal the old balance plus 5% of the old balance You could solve this problem as you did for the retail sales program, but you could also do a little algebra “off line”, observe that
balance + 0.05 * balance is equivalent to
1.05 * balance, and implement the solution as follows:
// Earn 5% interest balance = 1.05 * balance;
This pattern is so common that many programming languages include compound assignment operators to make it even easier to use. Such operators consist of multiple characters: the symbol for the arithmetic operator followed immediately by the symbol for the assignment operator. Note that, since a compound operator is an operator, it cannot contain white space (e.g., spaces, tabs, carriage returns, line feeds) between the characters. For example, the grading and banking examples can be written using compound assignment operators as follows:
// Reduce a grade by a late penalty grade -= latePenalty; // Earn 5% interest balance *= 1.05;
Beginning programmers need to be a little careful when using compound assignment operators. To see why, consider the following two statements:
i =+ 1; j =- 1;
While they look like they use compound assignment operators, they do not — compound assignment operators end with the character that is used for the assignment operator, they don’t start with it. That is,
+= is a compound assignment operator, but
=+ is not.
However, both of these statements are syntactically valid and, hence, will compile. This is because they use the assignment operator (i.e.,
=) followed be the unary “positive” (i.e.,
+) or “negative” (i.e.,
-) operators, without any white space between them. That is, they are the same as the following two statements:
i = +1; j = -1;
just with different spacing.
- This sentence is worded very carefully, and it is important to understand why. Note that it does not say "it adds the value 1 to the value in the memory location identified by
age". It is the assignment operator, not the addition operator, that changes the value in the memory location identified by
- Remember, you can also use parentheses to influence the order in which operators are evaluated. For example, in this case, one could avoid any confusion by writing
price = price - (0.25 * price);This is a question of style and doesn't change the pattern. ↵