Section 5.5 Numeric Data and Operators
Java has two kinds of numeric data: integers, which have no fractional part, and real numbers or floatingpoint numbers, which contain a fractional component.
Java recognizes four different kinds of integers: byte
, short
, int
, and long
, which 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
, which are also distinguished by the number of bits used to represent them. See TableĀ 5.5.1.
Subsection 5.5.1 Primitive Numeric Types
Type  Bits  Range of Values 
byte 
Ā 8  \(128 to +127\) 
short 
16  \(32768 \hbox{ to } 32767\) 
int 
32  \(2147483648 \hbox{ to } 2147483647\) 
long 
64  \(2^{63} \hbox{ to } 2^{63}1\) 
float 
32  \(3.40292347E+38 \hbox{ to } +3.40292347E+38\) 
double 
64  \(1.79769313486231570E+308 \hbox{ 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.
Definition 5.5.2.
An nbit quantity can represent \(2^n\) different values.As illustrated in TableĀ 5.5.1, 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 \(2^{32}\) different int
values, which range from \(2{,}147{,}483{,}648\) to \(2{,}147{,}483{,}647\text{,}\) that is, from \(2^{31}\) to \((2^{31} 1)\text{.}\) Similarly, an 8bit integer, a byte
, can represent \(2^8\) or 256 different values, ranging from \(128\) to \(+127\text{.}\) A 16bit integer, a short
, can represent \(2^{16}\) different values, which range from \(32768\) to \(32767\text{.}\) And a 64bit integer, a long
, can represent whole number values ranging from \(2^{63}\) to \(2^{63}1\text{.}\)
For floatingpoint numbers, a 32bit float
type can represent \(2^{32}\) different real numbers and a 64bit double
value can represent \(2^{64}\) different real numbers.
Principle 5.5.3. 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.
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 tradeoffs have been made in order to come up with practical implementations.
One tradeoff 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 \(\frac{1}{10}\text{.}\) This inability to exactly represent a value is known as roundoff error. Being unable to represent certain values can cause problems in a program. For example, it might be difficult to represent dollars and cents accurately in a program.
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.
Principle 5.5.4. 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.
Exercises SelfStudy Exercises
1. FillIn Binary.
List all of the binary values that can be represented in 4 bitsthat is, all values in the range 0000 to 1111 in order separated by commas:
Start from 0000, 0001, ...
2. 6bit Values.
If a 6bit representation were used for an integer type, how many different integers could be represented?
With 3 bits, you can represent 3^2 = 32 values.
3. Data Type.
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?
Some data types you could use are byte
, short
, int
, double
, and long
Subsection 5.5.2 Arithmetic Operators
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 the Ć. The arithmetic operators are binary operators, meaning that they each take two operands. TableĀ 5.5.5 compares expressions involving the Java operators with their standard algebraic counterparts.
Operation  Operator  Java  Algebra 
Addition  \(+\)  \(x + 2\)  \(x + 2\) 
Subtraction  \(\)  \(m  2\)  \(m  2\) 
Multiplication  *  \(m\) * \(2\)  \(2m \hbox{ or } m \times 2\) 
Division  /  \(x / y\)  \(x \div y \hbox{ or } \frac{x}{y}\) 
Modulus  %  \(x \% y\)  \(x \hbox{ modulo } y\) (for integers \(x\) and \(y\)) 
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 floatingpoint result
3 / 2.0 ==> value 1.5 A floatingpoint result
3.0 / 2 ==> value 1.5 A floatingpoint 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.
Principle 5.5.6. 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 floatingpoint 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 5 ā that is, 2 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
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 \div 5\text{,}\) 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\text{.}\) When you do long division on \(7 \div 5\text{,}\) 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\text{.}\)
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");
More generally, we could use the mod operator to define divisibility by 3, 4, 10, or by any number.
Activity 5.5.1.
Try the expressions containing the % operator below to see how they can be used to check for even or odd numbers. All even numbers are divisible (with no remainder) by 2. Add another if statement that checks whether age2 is even using the % operator. Then, test if it's divisible by 3.
Exercises SelfStudy Exercises
1. Evaluate div and mod.
2. Evaluate Decimal Expressions.
Subsection 5.5.3 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 floatingpoint number, Java promotes the integer into a floatingpoint value and performs a floatingpoint operation.
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 floatingpoint 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 lead to loss of information. This leads to the following rule:
Principle 5.5.7. Integer Promotion.
In an operation that contains an integer and a floatingpoint operand, the integer is promoted to a floatingpoint value before the operation is performed.
This rule is actually an instance of a more general rule: 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 short
s. Conversion of short
to byte
would not be possible because there's no way to represent the value 32000 as a byte
.
It is important to note 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 following the general rule:
Principle 5.5.8. Type Promotion Rule.
In general, when two different types are involved in an operation, the smaller type ā i.e.,the one with fewer bits ā is converted to the larger type before the operation is performed. To do otherwise would risk losing information.
TableĀ 5.5.9 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 literals ā such as \(56\) or \(108\) ā are represented as int
types in Java.
If either operand is  The other is promoted to  
double 
double 

float 
float 

long 
long 

byte orshort

int 
Exercises SelfStudy Exercises
1. Evaluate Type Promotion.
Subsection 5.5.4 Operator Precedence
Precedence Order  Operator  Operation 
1  \(( \; )\)  Parentheses 
2  \(\ast \;\; / \;\; \%\)  Multiplication, Division, Modulus 
3  \(+ \;\; \)  Addition, Subtraction 
The builtin precedence order for arithmetic operators is shown in TableĀ 5.5.10. 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:
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.
Principle 5.5.11. 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.
Exercises SelfStudy Exercises
1. Evaluate Expressions.
2. Evaluate Expressions.
Subsection 5.5.5 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.
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 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
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
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.5.12 summarizes the increment and decrement operators. The unary increment and decrement operators have higher precedence than any of the binary arithmetic operators.
Expression  Operation  Interpretation 
\(j = ++k\)  Preincrement  \(k=k+1;j=k;\) 
\(j = k++\)  Postincrement  \(j=k;k=k+1;\) 
\(j = k\)  Predecrement  \(k=k1;j=k;\) 
\(j = k\)  Postdecrement  \(j=k;k=k1;\) 
Principle 5.5.13. 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.
Principle 5.5.14. PROGRAMMING TIP: Increment and Decrement Operators.
Because of their subtle behavior, be careful in how you use the unary increment and decrement operators. They are most appropriate and useful for incrementing and decrementing loop variables, as we'll see later.
Exercises SelfStudy Exercises
1. Evaluate Increment/Decrement Expressions.
k==5, j==5
>k==5, j==6
k==6, j==6
k==5, j==4
k==4, j==4
Subsection 5.5.6 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 floatingpoint 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 righthand side is first evaluated and then added to the current value of the variable on its lefthand side.
TableĀ 5.5.15 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 righthand 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.
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;\) 
\(\ast \!=\)  Multiplication then assignment  \(m\ \ast \!=\ 3;\)  \(m = m\,\ast \,3;\) 
\(/\!=\)  Division then assignment  \(m\ /\!=\ 3;\)  \(m = m / 3;\) 
\(\%\!=\)  Remainder then assignment  \(m\ \%\!=\ 3;\)  \(m = m \% 3;\) 
Activity 5.5.2.
Run the code below to see what the ++ and shorcut operators do. Click on the Show Code Lens button to trace through the code and the variable values change in the visualizer.
Exercises SelfStudy Exercises
1. Evaluate Shortcut Expressions.
2.
Write four different statements that add 1 to the variable k
(which has been declared as an int).
Subsection 5.5.7 Relational Operators
There are several relational operations that can be performed on numbers: \(\lt\text{,}\) \(>\text{,}\) \(\lt =\text{,}\) \(> =\text{,}\) \(= =\text{,}\) and \(!\!=\text{.}\) These correspond to the algebraic operators \(\lt\text{,}\) \(>\text{,}\) \(\leq\text{,}\) \(\geq\text{,}\) \(=\text{,}\) and \(\neq\text{.}\) Each of these operators takes two operands (integer or real) and returns a boolean result. They are defined in TableĀ 5.5.16.
Operator  Operation  Java Expression 
\(\lt\)  Less than  \(5 \lt 10\) 
\(>\)  Greater than  \(10 > 5\) 
\(\lt =\)  Less than or equal to  \(5 \lt = 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 is so the equality operator can be distinguished from the assignment operator. Also, less than or equal to (\(\lt\)=), greater than or equal to (\(>\)=), and not equal to (!=) require two symbols, instead of the familiar \(\leq\text{,}\) \(\geq\text{,}\) and \(\neq\) from algebra. In each case, the two symbols should be consecutive. It is an error in Java for a space to appear between the \(\lt\) and = in \(\lt =\text{.}\)
Principle 5.5.17. DEBUGGING TIP: Equality and Assignment.
A common semantic error among beginning programmers is to use the assignment operator (=) when the equality operator (==) is intended.
Activity 5.5.3.
Run the code below and try changing the value of x to get each of the three possible lines in the conditional to print.
Among the relational operators, the inequalities (\(\lt\text{,}\) \(>\text{,}\) \(\lt =\text{,}\) 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.5.18 includes all of the numeric operators introduced soĀ far.
Precedence Order  Operator  Operation 
1  \((\,)\)  Parentheses 
2  \(+\!+\ \ \)  Increment, decrement 
3  \(\ast \ \ /\ \ \%\)  Multiplication, division, modulus 
4  \(+\ \ \)  Addition, subtraction 
5  \(\lt \,\,\,\,>\ \ \lt =\ \ > =\)  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 )
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 illformed 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.