Arithmetic Operations


Java's arithmetic operations fall into two categories: basic arithmetic (addition, subtraction, multiplication, and division), and some more exotic operations such as modulo and shifting. We will begin by looking at the simple operations.

Basic Arithmetic

The following code computes and prints out the sum, difference, product, and quotient of two numbers:

public class C3 {   public static void main(String[] args)   {     int   x, y;         // Inputs     int   sum;          // x plus y     int   diff;         // x minus y     int   product;      // x times y     int   quotient;     // x divided by y     /* First assign initial values to        the x and y inputs. */     x = 12;     y = 3;     // Now do arithmetic.     sum = x + y;     System.out.println("sum = " + sum);     diff = x - y;     System.out.println("diff = " + diff);     product = x * y;     System.out.println("product = " + product);     quotient = x / y;     System.out.println("quotient = " + quotient);   } }

Note the use of the asterisk (*) to indicate multiplication. The other three symbols (+, -, and /) are recognizable from standard arithmetic. These symbols (as well as a few others that we'll see later on in this chapter) are known as binary operators. Here the word binary indicates that the operators work on two numbers at a time, known as operands. Most Java operators are binary, but there are several unary operators that each take a single operand. There is even a trinary operator that takes three operands. (We will postpone discussion of the trinary operator until Chapter 5, "Conditionals and Loops.")

There is nothing surprising about this program's output:

sum = 15 diff = 9 product = 36 quotient = 4

As mentioned in the previous chapter, the meaning of the equal sign (=) here is a bit different from its traditional mathematical meaning. In Java, the equal sign is called the assignment operator. It tells the computer to compute the value on the right-hand side of the equal sign (usually abbreviated rhs), and to store the result in the variable that appears on the left-hand side (usually abbreviated lhs). Until now, the rhs has been a literal value, but as this program shows, the rhs can also be a calculation. The calculation's arguments can be variables or literals, so the following lines would be valid:

int halfProduct; halfProduct = product / 2;

Java allows you to declare a variable and assign its initial value, all in a single statement. The preceding code can be rewritten as

int halfProduct = product / 2;

Later you can assign a different value to halfProduct. You can reassign values to variables as often as you like. Just don't declare the variable more than once, because the second declaration will cause a compiler error.

The lhs of an assignment can appear in its own rhs. Consider the following line:

x = x + 5;

If this were a line of algebra and not a computer-language statement, it would be ridiculous. When you subtract x from both sides, you get 0 = 5. But in Java, it is perfectly legal because the equal sign means assignment. The line says to add the value of x plus 5 and store the result back in x.

Precedence and Parentheses

Multiple operations can be combined in a single statement. For example, you might use the following code to compute the area of a circle whose radius is known:

double area = 3.14159 * r * r; // Pi-r-squared

Use caution when combining different operators in a single statement. It would be reasonable to expect the statement to be evaluated left to right, but Java doesn't do it that way. For example, you might expect that after the following line executes, the value of x is 502:

int x = 1000 + 4 / 2;

Actually, x is 1002. Java gives multiplication and division higher precedence than addition and subtraction. This means that in a statement such as the one above, any multiplication or

division is performed before any addition or subtraction, even if the addition and subtraction appear first. So the division happens first (4/2 = 2), and then the addition (1000+2 = 1002).

Note

Java has strict evaluation precedence rules that govern all the operations presented in this chapter. The precedence is summarized in Table 3.6.

If you don't like a statement's order of evaluation, as dictated by the precedence of its operators, you can use parentheses. Operations that appear in parentheses have higher precedence than operations that do not. So the following code really does compute a result of 502:

int x = (1000 + 4) / 2;

Parentheses can be nested, as the following example shows:

int x = 1+(2*(3-4)+(5-6)*(7+8));

The result is -16.

The EvaluatorLab animated illustration will help you get used to parentheses and operator precedence. To launch the program, type java eval.EvaluatorLab. You will see the display shown in Figure 3.1.

click to expand
Figure 3.1: EvaluatorLab

Type any arithmetic expression into the text field and press Enter. The arithmetic expression can consist of any combination of literal integers, parentheses, and the binary operations +, -, *, and /. Click on the Run button to see an animation of the evaluation of the expression. Click on Step to see an animation of just the next step in the expression's evaluation. The Run Lightspeed and Step Lightspeed buttons perform the evaluation immediately, without animation. Figure 3.2 shows the program after evaluating the configuration of Figure 3.2.

click to expand
Figure 3.2: EvaluatorLab after evaluation

Type the following expressions into EvaluatorLab and observe the results:

  • 1000+4/2

  • (1000+4)/2

  • 1+(2*(3-4)+(5-6)*(7+8))

The EvaluatorLab only works with integer data. In Java, integer addition, subtraction, and multiplication behave exactly as you would expect. Division, however, has a problem. Dividing an integer by an integer can produce a non-integer result. Be aware that when Java divides a byte, short, char, int, or long by a byte, short, char, int, or long, the result is truncated. This means that any fractional part is discarded. For example, 48 / 10 would be truncated from 4.8 to 4.

Truncation may seem like a problem, but it really isn't. If you are going to be dividing, and you know that the fractional parts of the results will be important, just use a floating-point data type (float or double) rather than an integer type. A good rule of thumb is to use integer types for quantities that can be counted, such as the number of employees or grizzly bears, and to use floating-point types for things that can be measured, such as weight or speed.

Bitwise Operations

A bitwise operation treats its operands as collections of individual unrelated bits, rather than as representations of numbers. You can only perform bitwise operations on integer data. Floats and doubles are not allowed.

There is one unary bitwise operator. Its symbol is the tilde (~). It toggles all the bits of its operand, changing all 0s to 1s and all 1s to 0s. Figure 3.3 illustrates the operation ~144.

click to expand
Figure 3.3: The unary bitwise operator ~

With a binary bitwise operation, the nth bit of the result is computed from the nth bits of the two operands. The three binary bitwise operations are and, or, and exclusive or. The operator symbols are &, |, and ^.

The "and" of two bits is 1 if both bits are 1. Otherwise, the result is 0. Another way to say this is that the result is 1 if one argument bit is 1 and the other argument bit is 1.

The "or" of two bits is 1 if either (or both) of the bits is 1. Otherwise, the result is 0. Another way to say this is that the result is 1 if one argument bit is 1 or the other argument bit is 1 (or both).

The "exclusive or" of two bits is 1 if either (but not both) of the bits is 1. Otherwise, the result is 0.

Table 3.1 shows the results of the three binary bitwise operations on all possible combinations of operand bits a and b.

Table 3.1: Binary Bitwise Operations

a&b

a|b

a^b

a,b = 0,0

0

0

0

a,b = 0,1

0

1

1

a,b = 1,0

0

1

1

a,b = 1,1

1

1

0

As you can see from the table, the only way for & to generate a 1 is if both operands are 1. The only way for | to generate a 0 is if both operands are 0. ^ generates a 1 if its two operands are different.

In practice, the binary bitwise operators work on integer values, not on integer bits. For example, if you take the "and" of two ints, bit 0 of the result will be the "and" of the bit 0s of the two operands. Bit 1 of the result will be the "and" of the bit 1s of the two operands, and so on through bit 31. This is illustrated in Figure 3.4.

click to expand
Figure 3.4: Bitwise "and"

As you can see, every bit in the result is computed solely from the corresponding bits in the two operands.

Modulo

Java supports some binary arithmetic operations that we don't often encounter outside the realm of computer programming: the modulo operation and three shift operations.

The symbol for modulo is the percent sign (%). The operation divides the first operand by the second operand and returns the remainder. So for example, 506 % 100 is 6, 507 % 100 is 7, and so on.

Shifting

Shifting operations move the bits of an integer operand to the left or right by some number of positions. There is one left-shift operation; its symbol is <<. There are two right-shift operations;their symbols are >> and >>>.

The left-shift operation is straightforward. The first operand is the value to be shifted. The second operand is the number of bit positions to shift by. Figure 3.5 illustrates 18 << 5.

click to expand
Figure 3.5: Left-shift: <<

As the figure shows, the high-order bits of the shifting value are discarded. The low-order bits are all set to 0.

The result of the shift in base-2 is 1001000000, which is 576. Is there any numerical relationship between 576 and the original value of 18? Yes, 576 is 18 times 32. Is there anything special about 32? Yes, 32 is 2 raised to the power of 5. In general, left-shifting x by y is the same as multiplying x by 2y. This is elegant, and it makes good sense. Left-shifting a value by, for example, 3 bit positions is like writing three 0s to the right of the number. In base-10, if you write three 0s to the right of a number, you have multiplied that number by 103 (that is, by 1000). It is not surprising that something similar happens in base-2.

There are two right-shift operations. One of them is bitwise, and the other is numeric.

The bitwise right-shift (>>>) is just the opposite of the left-shift: bits are moved to the right, any bits that fall off the right end are lost, and the left end is filled with 0s. This is illustrated in Figure 3.6.

click to expand
Figure 3.6: Bitwise right-shift: >>>

The original value in the figure has its sign bit set to 1, representing a negative number. The result has a sign bit of 0, since the >>> operation always shifts 0s into the left portion of the result. You can see that >>> always converts negative numbers to positive numbers that have no clear relationship to the original values. This is why the >>> shift is called bitwise. All it does is move bits.

The other shift operation is >>. It is different from >>> in only one respect: The left bits of the result are set to the sign bit of the original value, instead of being always set to 0. For positive numbers, the original sign bit is 0, so >>> is the same as >>. But for negative numbers, the result is very different, as Figure 3.7 shows.

click to expand
Figure 3.7: Numeric right-shift: >>

The sign of the result is always the sign of the original value. Does the result have any numerical relationship to the original? Yes, although it is hard to see the relationship when you look at Figure 3.7. It turns out that x >> y is the same as x / 2y.

The different right-shift operations can be confusing until you have some experience with them. The ShiftLab animated illustration will help you get that experience. Launch the program by typing java shift.ShiftLab. The display shows a 32-bit int value to be shifted, as illustrated in Figure. 3.8.

click to expand
Figure 3.8: ShiftLab

You can change the value by typing a base-10 number (positive or negative) into the text field, or by clicking on individual bits in the display. Select the desired shift operation (<<, >>, or >>>) and the desired shift size, and then click on the Go button. The program will animate the shift that you've specified. Figure 3.9 shows the result of "96 << 3".

click to expand
Figure 3.9: ShiftLab after shifting

Try viewing the following shifts:

10 << 10
16384 >> 14
-1 >>> 1
-1 >> 1
-1 >> 20
-2147483648 >>> 31

Unary Arithmetic

The unary arithmetic operators have the symbols + and -. These are the same as the symbols for binary addition and subtraction, so the compiler has to figure out from context which kind of operation you want. A + or - between two operands is a binary operator; a + or - with no operand to the left is unary.

The unary - operation just changes the sign of its operand. So for example, the following code prints out y = -5:

int x = 5; int y = -x; System.out.println("y = " + y);

The unary + operator maintains the sign of its operand. In other words, it doesn't really do anything.

++ and --

Two of the most common operations in programming are adding or subtracting 1 with a variable, and storing the result back in the variable. If the variable is called x, these operations can be programmed as follows:

x = x + 1; x = x - 1;

However, Java provides some convenient abbreviations. The first line can be abbreviated in either of the following ways:

x++; ++x;_

The second line can be abbreviated in either of the following ways:

x--; --x;

The following program shows these operators in action:

public class PlusPlusMinusMinus {   public static void main(String[] args)   {     int x = 10;     int y = x;     x++;     y--;     System.out.println("x=" + x + ", y=" + y);   } }

The output is

X=11, y=9

You can see that x has been incremented and y has been decremented.

When the operator appears after the operand, the rhs is first calculated as if the operator were not present. Then the rhs value is assigned to the lhs. Lastly, the operand of ++ or -- is incremented or decremented. For example:

public class PostDec {   public static void main(String[] args)   {     int x = 10;     int y = 1000 + x--;     System.out.println("x=" + x + ", y=" + y);   } }

The output is

X=9, y=1010

You can see that x, which was originally 10, must have been added to y before being decremented.

When ++ appears before its argument, it is called the pre-increment operator. When it appears after its argument, it is called the post-increment operator. Similarly, -- before its argument is called the pre-decrement operator, and -- after its argument is called the post-decrement operator.




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net