Section 5.3. Numeric Data and Operators


[Page 204 (continued)]

5.3. Numeric Data and Operators

Java has two kinds of numeric data: integers, which have no fractional part, and real numbers, or floating-point numbers, which contain a fractional component. Java recognizes four different kinds of integers: byte, short, int, and long. They are distinguished by the number of bits used to represent them. A binary digit, or bit, is a 0 or a 1. (Recall that computers read instructions as series of 0s and 1s.) Java has two different kinds of real numbers, float and double. These are also distinguished by the number of bits used to represent them. See Table 5.3.

Table 5.3. Java's numeric types

Type

Bits

Range of Values

byte

.8

-128 to +127

short

16

-32768 to 32767

int

32

-2147483648 to 2147483647

long

64

-263 to 263 - 1

float

32

-3.40292347E + 38 to +3.40292347E + 38

double

64

-1.79769313486231570E + 308 to +1.79769313486231570E + 308


The more bits a data type has, the more values it can represent. One bit can represent two possible values, 1 and 0, which can be used to stand for true and false, respectively. Two bits can represent four possible values: 00, 01, 10, and 11; three bits can represent eight possible values: 000, 001, 010, 100, 101, 110, 011, 111. And, in general, an n-bit quantity can represent 2n different values.

As illustrated in Table 5.3, the various integer types represent positive or negative whole numbers. Perhaps the most commonly used integer type in Java is the int type, which is represented in 32 bits. This means that Java can represent 232 different int values, which range from -2,147,483,648 to 2,147,483,647, that is, from -231 to (231-1). Similarly, an 8-bit integer, a byte, can represent 28 or 256 different values, ranging from -128 to +127. A 16-bit integer, a short, can represent 216 different values, which range from -32768 to 32767. And a 64-bit integer, a long, can represent whole-number values ranging from -263 to 263 - 1.

Integer data types


For floating-point numbers, a 32-bit float type can represent 232 different real numbers and a 64-bit double value can represent 264 different real numbers.

Effective Design: Platform Independence

In Java, a data type's size (number of bits) is part of its definition and, therefore, remains consistent across all platforms. In C and C++, the size of a data type is dependent on the compiler.



[Page 205]

It is worth noting that just as model airplanes are representations of real airplanes, Java's numeric types are representations, or models, of the numbers we deal with in mathematics. In designing Java's data types, various trade-offs have been made in order to come up with practical implementations.

Data types are abstractions


One trade-off is that the set of integers is infinite, but Java's int type can only represent a finite number of values. Similarly, Java cannot represent the infinite number of values that occur between, say, 1.111 and 1.112. So certain real numbers cannot be represented at all. For example, because Java uses binary numbers to represent its numeric types, one number that cannot be represented exactly is . This inability to exactly represent a value is known as round-off error. Being unable to represent certain values can cause problems in some programs. For example, it might be difficult to represent dollars and cents accurately.

Representation trade-offs


Round-off error


Another source of problems in dealing with numeric data is due to limits in their precision. For example, a decimal number represented as a double value can have a maximum of 17 significant digits, and a float can have a maximum of 8. A significant digit is one that contributes to the number's value. If you tried to store values such as 12345.6789 or 0.123456789 in a float variable, they would be rounded off to 12345.679 and 0.12345679, respectively, causing a possible error.

Debugging Tip: Significant Digits

In using numeric data, be sure the data type you choose has enough precision to represent the values your program needs.


Self-Study Exercises

Exercise 5.2

List all of the binary values that can be represented in 4 bitsthat is, all the values in the range 0000 to 1111.

Exercise 5.3

If a 6-bit representation were used for an integer type, how many different integers could be represented?

Exercise 5.4

If you were writing a program to process scientific data that had to be accurate to at least 12 significant (decimal) digits, what type of data would you use?

5.3.1. Numeric Operations

The operations that can be done on numeric data include the standard algebraic operations: addition (+), subtraction (-), multiplication (*), division (/), as well as the modulus (%) operator. Note that in Java, the multiplication symbol is * and not x. The arithmetic operators are binary operators, meaning that they each take two operands. Table 5.4 compares expressions involving the Java operators with their standard algebraic counterparts.

Table 5.4. The standard arithmetic operators in Java

Operation

Operator

Java

Algebra

Addition

+

x + 2

x + 2

Subtraction

-

m - 2

m - 2

Multiplication

*

m *2

2m or 2 x m

Division

/

x/y

x ÷ y or

Modulus

%

x%y

x modulo y (for integers x and y)


Numeric operators



[Page 206]

Although these operations should seem familiar, there are some important differences between their use in algebra and their use in a Java program. Consider the following list of expressions:

3 / 2     ==> value 1    An integer result 3.0 / 2.0 ==> value 1.5  A floating-point result 3 / 2.0   ==> value 1.5  A floating-point result 3.0 / 2   ==> value 1.5  A floating-point result 


In each of these cases we are dividing the quantity 3 by the quantity 2. However, different results are obtained depending on the type of the operands involved. When both operands are integers, as in (3/2), the result must also be an integer. Hence, (3/2) has the value 1, an integer. Because integers cannot have a fractional part, the 0.5 is simply discarded. Integer division (/) always gives an integer result. Thus, the value of (6/2) is 3 and the value of (7/2) is also 3. Because 3.5 is not an integer, the result of dividing 7 by 2 cannot be 3.5.

Integer division gives an integer result


Debugging Tip: Integer Division

A common source of error among beginning programmers is forgetting that integer division always gives an integer result.


On the other hand, when either operand is a real number, as in the last three cases, the result is a real number. Thus, while the same symbol (/) is used for dividing integers and real numbers, there are really two different operations involved here: integer division and floating-point division. Using the same symbol (/) for different operations (integer division and real division) is known as operator overloading. It is similar to method overloading, which was discussed in Chapter 3.

What if you want to keep the remainder of an integer division? Java provides the modulus operator (%), which takes two operands. The expression (7 % 5) gives the remainder after dividing 7 by 52 in this case. In general, the expression (m % n) (read m mod n) gives the remainder after m is divided by n. Here are several examples:

7 % 5  ==> 7 mod 5 equals 2 5 % 7  ==> 5 mod 7 equals 5 -7 % 5 ==> -7 mod 5 equals -2 7 % -5 ==> 7 mod -5 equals 2 


Modular arithmetic


The best way to interpret these examples is to perform long division on the operands, keeping both the quotient and the remainder. For example, when you do long division on -7 ÷ 5, you get a quotient of -1 and a remainder of -2. The quotient is the value of -7/5, and the remainder is the value of -7%5. When you do long division on 7÷-5, you get a quotient of -1 and a remainder of 2. The quotient is the value of 7/-5, and the remainder is the value of 7%-5.

We will encounter many practical uses for the modulus operator in our programs. For a simple example, we use it when we want to determine whether an integer is even or odd. Numbers that leave a 0 remainder when divided by 2 are even:

if (N % 2 == 0)     System.out.println(N + " is even"); 



[Page 207]

More generally, we could use the mod operator to define divisibility by 3, 4, 10, or by any number.

Numeric Promotion Rules

Java is considered a strongly typed language because all expressions in Java, such as (3/2), have a type associated with them. In cases where one arithmetic operand is an integer and one is a floating-point number, Java promotes the integer into a floating-point value and performs a floating-point operation.

Expressions have a type


Promotion is a matter of converting one type to another type. For example, in the expression (5 + 4.0), the value 5 must be promoted to 5.0 before floating-point addition can be performed on (5.0 + 4.0). Generally speaking, automatic promotions such as these are allowed in Java whenever it is possible to perform the promotion without loss of information. Because an integer (5) does not have a fractional component, no information will be lost in promoting it to a real number (5.0). On the other hand, you cannot automatically convert a real number (5.4) to an integer (5) because that might result in a loss of information. This leads to the following rule:

Java Language Rule: Integer Promotion

In an operation that contains an integer and a floating-point operand, the integer is promoted to a floating-point value before the operation is performed.


This rule is actually an instance of a more general rule, for whenever an expression involves operands of different types, some operands must be converted before the expression can be evaluated. Consider the following example:

byte n = 125; short m = 32000; n * m; 


In this case, (n * m) involves two different integer types, byte and short. Before evaluating this expression Java must first promote the byte to a short and carry out the operation as the multiplication of two shorts. Conversion of short to byte would not be possible because there is no way to represent the value 32000 as a byte.

Bear in mind that this conversion rule applies regardless of the actual values of the operands. In applying the rule, Java looks at the operand's type, not its value. So even if m were assigned a value that could be represented as a byte (for example, 100), the promotion would still go from smaller to larger type. This leads to the following general rule:

Java Language Rule: Type Promotion

In general, when two different types are involved in an operation, the smaller typethe one with fewer bitsis converted to the larger type before the operation is performed. To do otherwise would risk losing information.


Promotion is automatic



[Page 208]

Table 5.5 summarizes the actual promotion rules used by Java in evaluating expressions involving mixed operands. Note that the last rule implies that integer expressions involving byte or short or int are performed as int. This explains why integer literalssuch as 56 or -108are represented as int types in Java.

Table 5.5. Java promotion rules for mixed arithmetic operators. If two rules apply, choose the one that occurs first in this table.

If either operand is

The other is promoted to

double

double

float

float

long

long

byte or short

int


Self-Study Exercises

Exercise 5.5

Evaluate each of the following integer expressions:

  1. 8 / 2

  2. 9 / 2

  3. 6 / 8

  4. 9 % 2

  5. 8 % 6

  6. 6 % 8

  7. 8 % 4

  8. 4 % 8

Exercise 5.6

Evaluate each of the following expressions, paying special attention to the type of the result in each case:

  1. 8 / 2.0

  2. 9 / 2.0

  3. 6 / 8

  4. 0.0 / 2

  5. 8.0 / 6.0

Exercise 5.7

Suppose that the following variable declarations are made:

byte m = 3; short n = 4; int p = 5; long q = 6; double r = 7.0; 


Use type promotion rules to determine the type of expression and then evaluate each of the following expressions:

  1. m + n

  2. p * q

  3. m + n + r

  4. p * q * m

  5. r - m

5.3.2. Operator Precedence

Arithmetic precedence order


The built-in precedence order for arithmetic operators is shown in Table 5.6. Parenthesized expressions have highest precedence and are evaluated first. Next come the multiplication, division, and modulus operators, followed by addition and subtraction. When we have an unparenthesized expression that involves both multiplication and addition, the multiplication would be done first, even if it occurs to the right of the plus sign. Operators at the same level in the precedence hierarchy are evaluated from left to right. For example, consider the following expression:


[Page 209]

Table 5.6. Precedence order of the arithmetic operators

Precedence Order

Operator

Operation

1

( )

Parentheses

2

* / %

Multiplication, Division, Modulus

3

+ -

Addition, Subtraction


9 + 6 - 3 * 6 / 2 


In this case, the first operation to be applied will be the multiplication (*), followed by division (/), followed by addition (+), and then finally the subtraction (-). We can use parentheses to clarify the order of evaluation. A parenthesized expression is evaluated outward from the innermost set of parentheses:

Step 1. ( (9 + 6) - ((3 * 6) / 2 ) ) Step 2. ( (9 + 6) - (18 / 2 ) ) Step 3. ( (9 + 6) - 9 ) Step 4. ( 15 - 9 ) Step 5. 6 


Parentheses can (and should) always be used to clarify the order of operations in an expression. For example, addition will be performed before multiplication in the following expression:

(a + b) * c 


Another reason to use parentheses is that Java's precedence and promotion rules will sometimes lead to expressions that look fine but contain subtle errors. For example, consider the following expressions:

System.out.println(5/3/2.0);   // 0.5 System.out.println(5/(3/2.0)); // 3.33 


The first gives a result of 0.5, but the use of parentheses in the second gives a result of 3.33. If the second is the expected interpretation, then the parentheses here helped avoid a subtle semantic error.

Java Programming Tip: Parenthesize!

To avoid subtle bugs caused by Java's precedence and promotion rules, use parentheses to specify the order of evaluation in an expression.



[Page 210]
Self-Study Exercise

Exercise 5.8

Parenthesize and then evaluate each of the expressions that follow, taking care to observe operator precedence rules. Watch for subtle syntax errors.

  1. 4 + 5.0 * 6

  2. (4 + 5) * 6

  3. 4 + 5 / 6

  4. (4 + 5) / 6

  5. 4 + 5 % 3

  6. (4 + 5) % 3

  7. 9 % 2 * 7 / 3

  8. 5.0 / 2 * 3

5.3.3. Increment and Decrement Operators

Java provides a number of unary operators that are used to increment or decrement an integer variable. For example, the expression k++ uses the increment operator ++ to increment the value of the integer variable k. The expression k++ is equivalent to the following Java statements:

int k; k = k + 1;// Add 1 to k and assign the result back to k 


The unary ++ operator applies to a single-integer operand, in this case to the variable k. It increments k's value by 1 and assigns the result back to k. It may be used either as a preincrement or a postincrement operator. In the expression k++, the operator follows the operand, indicating that it is being used as a postincrement operator. This means that the increment operation is done after the operand's value is used.

Preincrement and postincrement


Contrast that with the expression ++k in which the ++ operator precedes its operand. In this case, it is used as a preincrement operator, which means that the increment operation is done before the operand's value is used.

When they are used in isolation, there is no practical difference between k++ and ++k. Both are equivalent to k = k + 1. However, when used in conjunction with other operators, there is a significant difference between preincrement and postincrement. For example, in the following code segment,

int j = 0, k = 0;   // Initially both j and k are 0 j = ++k;            // Final values of both j and k are 1 


the variable k is incremented before its value is assigned to j. After execution of the assignment statement, j will equal 1 and k will equal 1. The sequence is equivalent to

Precedence order


int j = 0, k = 0;   // Initially both j and k are 0 k = k + 1; j = k;              // Final values of both j and k are 1 


However, in the following example,

int i = 0, k = 0; // Initially both i and k are 0 i = k++;          // Final value of i is 0 and k is 1 



[Page 211]

the variable k is incremented after its value is assigned to i. After execution of the assignment statement, i will have the value 0 and k will have the value 1. The preceding sequence is equivalent to

int i = 0, k = 0;   // Initially both i and k are 0 i = k; k = k + 1;          // Final value of i is 0 and k is 1 


In addition to the increment operator, Java also supplies the decrement operator --, which can also be used in the predecrement and postdecrement forms. The expression -- k will first decrement k's value by 1 and then use k in any expression in which it is embedded. The expression k-- will use the current value of k in the expression in which k is contained and then it will decrement k's value by 1. Table 5.7 summarizes the increment and decrement operators. The unary increment and decrement operators have higher precedence than any of the binary arithmetic operators.

Table 5.7. Java's increment and decrement operators

Expression

Operation

Interpretation

j = ++ k

Preincrement

k = k + 1;j = k;

j = k ++

Postincrement

j = k; k = k + 1;

j = --k

Predecrement

k = k - 1; j = k;

j = k --

Postdecrement

j = k; k = k - 1;


Predecrement and postdecrement


Java Language Rule: Pre- and Postincrement/Decrement

If an expression like ++k or --k occurs in an expression, k is incremented or decremented before its value is used in the rest of the expression. If an expression like k++ or k-- occurs in an expression, k is incremented or decremented after its value is used in the rest of the expression.


Java Programming Tip: Increment and Decrement Operators

Because of their subtle behavior, be careful how you use the unary increment and decrement operators. They are most appropriate and useful for incrementing and decrementing loop variables, as we will see later.


Self-Study Exercise

Exercise 5.9

What value will j and k have after each of the calculations that follow? Assume that k has the value 0 and j has the value 5 before each operation is performed.

  1. k = j;

  2. k = j++;

  3. k = ++j;

  4. k = j--;

  5. k = --j;


[Page 212]

5.3.4. Assignment Operators

In addition to the simple assignment operator (=), Java supplies a number of shortcut assignment operators that allow you to combine an arithmetic operation and an assignment in one operation. These operations can be used with either integer or floating-point operands. For example, the += operator allows you to combine addition and assignment into one expression. The statement

k += 3; 


is equivalent to the statement

k = k + 3; 


Similarly, the statement

r += 3.5 + 2.0 * 9.3 ; 


is equivalent to

r = r + (3.5 + 2.0 * 9.3);  // i.e., r = r + 22.1; 


As these examples illustrate, when using the += operator, the expression on its right-hand side is first evaluated and then added to the current value of the variable on its left-hand side.

Table 5.8 lists the other assignment operators that can be used in combination with the arithmetic operators. For each of these operations, the interpretation is the same: evaluate the expression on the right-hand side of the operator and then perform the arithmetic operation (such as addition or multiplication) to the current value of the variable on the left of the operator.

Table 5.8. Java's assignment operators

Operator

Operation

Example

Interpretation

=

Simple assignment

m = n;

m = n;

+=

Addition then assignment

m += 3;

m = m + 3;

-=

Subtraction then assignment

m -= 3;

m = m - 3;

*=

Multiplication then assignment

m *= 3;

m = m * 3;

/=

Division then assignment

m /= 3;

m = m/3;

%=

Remainder then assignment

m %= 3;

m = m%3;


Self-Study Exercises

Exercise 5.10

What value will j and k have after each of the calculations that follow? Assume that k has the value 10 and that j has the value 5 before each operation is performed.

  1. k += j;

  2. k -= j++;

  3. k *= ++j * 2;

  4. k /= 25 * j--;

  5. k %= j - 3;

Exercise 5.11

Write four different statements that add 1 to the int k.


[Page 213]

5.3.5. Relational Operators

There are several relational operations that can be performed on integers: <, >, < =, > =, ==, and ! =. These correspond to the algebraic operators <, >, , , =, and . Each of these operators takes two operands (integer or real) and returns a boolean result. They are defined in Table 5.9.

Table 5.9. Relational operators

Operator

Operation

Java Expression

<

Less than

5 < 10

>

Greater than

10 > 5

<=

Less than or equal to

5 <= 10

>=

Greater than or equal to

10 >= 5

= =

Equal to

5 = = 5

!=

Not equal to

5 != 4


Note that several of these relational operators require two symbols in Java. Thus, the familiar equals sign (=) is replaced in Java by ==. This ensures that the equality operator can be distinguished from the assignment operator. Less than or equal to (< =), greater than or equal to (> =), and not equal to (!=) also require two symbols instead of the familiar , , and from algebra. In each case, the two symbols should be consecutive. It is an error in Java for a space to appear between the < and = in < =.

Equals vs. assigns


Debugging Tip: Equality and Assignment

A common semantic error of beginning programmers is to use the assignment operator (=) when the equality operator (==) is intended.


Among the relational operators, the inequalities (<, >, < =, and > =) have higher precedence than the equality operators (== and !=). In an expression that involves both kinds of operators, the inequalities would be evaluated first. Otherwise, the expression is evaluated from left to right.

Taken as a group the relational operators have lower precedence than the arithmetic operators. Therefore, in evaluating an expression that involves both arithmetic and relational operators, the arithmetic operations are done first. Table 5.10 includes all of the numeric operators introduced so far.

Table 5.10. Numeric operator precedence including relations
(This item is displayed on page 214 in the print version)

Precedence Order

Operator

Operation

1

( )

Parentheses

2

++ --

Increment, decrement

3

* / %

Multiplication, division, modulus

4

+ -

Addition, subtraction

5

< > < = > =

Relational operators

6

= = !=

Equality operators


To take an example, let us evaluate the following complex expression:

9 + 6 <= 25 * 4 + 2 


To clarify the implicit operator precedence, we first parenthesize the expression

( 9 + 6 ) <= ( (25 * 4 ) + 2 ) 



[Page 214]

and then evaluate it step by step:

Step 1. ( 9 + 6 ) <= ( (25 * 4 ) + 2 ) Step 2. ( 9 + 6 ) <= ( 100 + 2 ) Step 3. 15 <= 102 Step 4. true 


The following expression is an example of an ill-formed expression:

9 + 6 <= 25 * 4 == 2 


That the expression is ill-formed becomes obvious if we parenthesize it and then attempt to evaluate it:

Step 1. ( ( 9 + 6 ) <= ( 25 * 4 ) ) == 2 Step 2. ( 15 <= 100 ) == 2 Step 3. true == 2     // Syntax error results here 


The problem here is that the expression TRue == 2 is an attempt to compare an int and a boolean value, which can't be done. As with any other binary operator, the == operator requires that both of its operands be of the same type. This is another example of Java's strong type checking.

Strong typing


Self-Study Exercises

Exercise 5.12

For each of these questions, what is the value of m? Assume that k equals 2, j equals 3, and m equals 10 before each question. Don't forget about precedence.

  1. m = j++ + k ;

  2. m = ++j + k;

  3. m += j + k;

  4. m *= j++ + k++;

  5. m *= ++j + ++k;

Exercise 5.13

Evaluate each of the following expressions, taking care to observe operator precedence rules. If an expression is illegal, mark it illegal and explain why.

  1. 4 + 5 == 6 * 2

  2. (4 + 5) <= 6 / 3

  3. 4 + 5 / 6 >= 10 % 2

  4. (4 = 5) / 6

  5. 4 + 5 % 3 != 7 - 2

  6. (4 + 5) % 3 = 10 -4

  7. 9 % 2 * 7 / 3 > 17




Java, Java, Java(c) Object-Orienting Problem Solving
Java, Java, Java, Object-Oriented Problem Solving (3rd Edition)
ISBN: 0131474340
EAN: 2147483647
Year: 2005
Pages: 275

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