Chapter 3
IN THIS CHAPTER
Dealing with operators, such as +, –, *, and /
Creating finely crafted expressions
Incrementing and decrementing
Accepting an assignment
Using the Math class
Formatting your numbers
Seeing strange things that can happen with numbers
In Book 2, Chapter 2, you discover the various primitive numeric types that are supported by Java. In this chapter, you build on that knowledge by doing basic operations with numbers. Much of this chapter focuses on the complex topic of expressions, which combine numbers with operators to perform calculations. This chapter also covers performing advanced calculations using the Math
class and techniques for formatting numbers when you display them. In addition, you find out why Java's math operations sometimes produce results you may not expect.
An operator is a special symbol or keyword that’s used to designate a mathematical operation or some other type of operation that can be performed on one or more values, called operands. In all, Java has about 40 operators. This chapter focuses on the operators that do arithmetic. These arithmetic operators — seven of them in all, summarized in Table 3-1 — perform basic arithmetic operations, such as addition, subtraction, multiplication, and division.
TABLE 3-1 Java’s Arithmetic Operators
Operator |
Description |
|
Addition |
|
Subtraction |
|
Multiplication |
|
Division |
|
Remainder (Modulus) |
|
Increment |
|
Decrement |
The following section of code can help clarify how these operators work for int
types:
int a = 32, b = 5;
int c = a + b; // c is 37
int d = a - b; // d is 27
int e = a * b; // e is 160
int f = a / b; // f is 5 (32 / 5 is 6 remainder 2)
int g = a % b; // g is 2 (32 / 5 is 6 remainder 2)
a++; // a is now 33
b--; // b is now 4
Notice that for division, the result is truncated. Thus 32 / 5
returns 6
, not 6.4
. For more information about integer division, see the section “Dividing Integers,” later in this chapter.
Here's how the operators work for double
values:
double x = 5.5, y = 2.0;
double m = x + y; // m is 7.5
double n = x - y; // n is 3.5
double o = x * y; // o is 11.0
double p = x / y; // p is 2.75
double q = x % y; // q is 1.5
x++; // x is now 6.5
y--; // y is now 1.0
int a = 21, b = 6;
double answer = a / b; // answer = 3.0
If that's not what you want, you can cast one of the operands to a double
before performing the division. (Casting an operand means converting its value from one data type to another.) Here’s how:
int a = 21, b = 6;
double answer = (double)a / b; // answer = 3.5
The moral of the story is that if you want to divide int
values and get an accurate double
result, you must cast at least one of the int
values to a double
.
int x;
y = 4x; // error, this line won't compile
%
) is also called a modulus operator. It returns the remainder when the first operand is divided by the second operand. The remainder operator is often used to determine whether one number is evenly divisible by another, in which case the result is zero. For more information, see the next section, “Dividing Integers.”a = ( (x + 4) * 7 ) / (y * x);
a=((x+4)*7)/(y*x);
Just remember that a little bit of white space never hurt anyone, and sometimes it helps make Java a little more readable.
When you divide one integer into another, the result is always another integer. Any remainder is simply discarded, and the answer is not rounded up. 5 / 4
gives the result 1
, for example, and 3 / 4
gives the result 0
. If you want to know that 5 / 4
is actually 1.25
or that 3 / 4
is actually 0.75
, you need to use floats or doubles instead of integers.
If you need to know what the remainder is when you divide two integers, use the remainder operator (%
). Suppose that you have a certain number of marbles to give away and a certain number of children to give them to. The program in Listing 3-1 lets you enter the number of marbles and the number of children. Then it calculates the number of marbles to give to each child and the number of marbles you have left over.
Here's a sample of the console output for this program, where the number of marbles entered is 93
and the number of children is 5
:
Welcome to the marble divvy-upper.
Number of marbles: 93
Number of children: 5
Give each child 18 marbles.
You will have 3 marbles left over.
LISTING 3-1 A Program That Divvies Up Marbles
import java.util.Scanner;→1
public class MarblesApp
{
static Scanner sc = new Scanner(System.in);→4
public static void main(String[] args)
{
// declarations→7
int numberOfMarbles;
int numberOfChildren;
int marblesPerChild;
int marblesLeftOver;→11
// get the input data→13
System.out.println("Welcome to the marble divvy-upper.");
System.out.print("Number of marbles: ");
numberOfMarbles = sc.nextInt();
System.out.print("Number of children: ");
numberOfChildren = sc.nextInt();→18
// calculate the results
marblesPerChild = numberOfMarbles / numberOfChildren;→21
marblesLeftOver = numberOfMarbles % numberOfChildren;→22
// print the results→24
System.out.println("Give each child " +
marblesPerChild + " marbles.");
System.out.println("You will have " +
marblesLeftOver + " marbles left over.");
}
}→30
The following paragraphs describe the key lines in this program:
java.util.Scanner
class so that the program can use it to get input from the user.Scanner
object and assigns it to a class variable so that it can be used in any method in the class.int a = 29; // any value will do
int b = 3; // any value will do
int c = a / b;
int d = a % b;
int e = (c * b) + d; // e will always equal a
You can combine operators to form complicated expressions. When you do, the order in which the operations are carried out is determined by the precedence of each operator in the expression. The order of precedence for the arithmetic operators is
++
) and decrement (--
) operators are evaluated first.+
or -
) are applied.*
), division (/
), and remainder (%
) operators are evaluated.+
) and subtraction (-
) operators are applied.In the expression a + b * c
, for example, multiplication has a higher precedence than addition. Thus b
is multiplied by c
first. Then the result of that multiplication is added to a
.
If an expression includes two or more operators at the same order of precedence, the operators are evaluated left to right. Thus, in the expression a * b / c
, a
is multiplied by b
and then the result is divided by c
.
If you want, you can use parentheses to change the order in which operations are performed. Operations within parentheses are always performed before operations that aren't in parentheses. Thus, in the expression (a + b) * c
, a
is added to b
first. Then the result is multiplied by c
.
If an expression has two or more sets of parentheses, the operations in the innermost set are performed first. In the expression (a * (b + c)) / d
, b
is added to c
. Then the result is multiplied by a
. Finally, that result is divided by d
.
int a = 5, b = 6, c = 7;
int d1 = a * b / c; // d1 is 4
int d2 = a * (b / c); // d2 is 0
This difference occurs because integer division always returns an integer result, which is a truncated version of the actual result. Thus, in the first expression, a
is first multiplied by b
, giving a result of 30
. Then this result is divided by c
. Truncating the answer gives a result of 4
. But in the second expression, b
is first divided by c
, which gives a truncated result of 0
. Then this result is multiplied by a
, giving a final answer of 0
.
The unary plus and minus operators let you change the sign of an operand. Note that the actual operator used for these operations is the same as the binary addition and subtraction operators. The compiler figures out whether you mean to use the binary or the unary version of these operators by examining the expression.
int a = 5; // a is 5
int b = -a; // b is -5
int c = -b; // c is +5
int a = -5; // a is -5
int b = +a; // b is -5
a = 5; // a is now 5
int c = +a; // c is 5
Notice that if a
starts out positive, +a
is also positive. But if a
starts out negative, +a
is still negative. Thus the unary plus operator has no effect. I guess Java provides the unary plus operator out of a need for balance.
You can also use these operators with more complex expressions, like this:
int a = 3, b = 4, c = 5;
int d = a * -(b + c); // d is -27
Here, b
is added to c
, giving a result of 9
. Then the unary minus operator is applied, giving a result of -9
. Finally, -9
is multiplied by a
, giving a result of -27
.
One of the most common operations in computer programming is adding or subtracting 1 from a variable. Adding 1 to a variable is called incrementing the variable. Subtracting 1 is called decrementing. The traditional way to increment a variable is this:
a = a + 1;
Here the expression a + 1
is calculated, and the result is assigned to the variable a
.
Java provides an easier way to do this type of calculation: the increment (++
) and decrement (--
) operators. These unary operators apply to a single variable. Thus, to increment the variable a
, you can code just this:
a++;
Note that an expression that uses an increment or decrement operator is a statement by itself. That's because the increment or decrement operator is also a type of assignment operator, as it changes the value of the variable it applies to.
a = b * 5++; // can't increment the number 5
a = (b * 5)++; // can't increment the expression (b * 5)
Note that you can use an increment or decrement operator in an assignment statement. Here’s an example:
int a = 5;
int b = a--; // both a and b are set to 4
When the second statement is executed, the expression a--
is evaluated first, so a
is set to 4
. Then the new value of a
is assigned to b
. Thus both a
and b
are set to 4
.
Confused yet? A simple example can clear things up. First, consider these statements with an expression that uses a postfix increment:
int a = 5;
int b = 3;
int c = a * b++; // c is set to 15
When the expression in the third statement is evaluated, the original value of b
— 3
— is used in the multiplication. Thus c
is set to 15
. Then b
is incremented to 4
.
Now consider this version, with a prefix increment:
int a = 5;
int b = 3;
int c = a * ++b; // c is set to 20
This time, b
is incremented before the multiplication is performed, so c
is set to 20
. Either way, b
ends up set to 4
.
Similarly, consider this example:
int a = 5;
int b = a--; // b is set to 5, a is set to 4.
This example is similar to an earlier example, but this time the postfix decrement operator is used. When the second statement is executed, the value of a
is assigned to b
. Then a
is decremented. As a result, b
is set to 5
, and a
is set to 4
.
b++;
c = a * b;
instead of
c = a * ++b;
In the first version, it’s crystal-clear that b
is incremented before the multiplication is done.
The standard assignment operator (=
) is used to assign the result of an expression to a variable. In its simplest form, you code it like this:
variable = expression;
Here's an example:
int a = (b * c) / 4;
You’ve already seen plenty of examples of assignment statements like this one, so I won’t belabor this point any further. I do want to point out — just for the record — that you cannot code an arithmetic expression on the left side of an equal sign. Thus the following statement doesn’t compile:
int a;
a + 3 = (b * c);
The key to understanding the rest of this section is realizing that in Java, assignments are expressions, not statements. In other words, a = 5
is an assignment expression, not an assignment statement. It becomes an assignment statement only when you add a semicolon to the end.
The result of an assignment expression is the value that’s assigned to the variable. The result of the expression a = 5
, for example, is 5
. Likewise, the result of the expression a = (b + c) * d
is the result of the expression (b + c) * d
.
The implication is that you can use assignment expressions in the middle of other expressions. The following example is legal:
int a;
int b;
a = (b = 3) * 2; // a is 6, b is 3
As in any expression, the part of the expression inside the parentheses is evaluated first. Thus, b
is assigned the value 3
. Then the multiplication is performed, and the result (6
) is assigned to the variable a
.
Now consider a more complicated case:
int a;
int b = 2;
a = (b = 3) * b; // a is 9, b is 3
What's happening here is that the expression in the parentheses is evaluated first, which means that b
is set to 3
before the multiplication is performed.
The parentheses are important in the previous example because without parentheses, the assignment operator is the last operator to be evaluated in Java's order of precedence. Consider one more example:
int a;
int b = 2;
a = b = 3 * b; // a is 6, b is 6
This time, the multiplication 3 * b
is performed first, giving a result of 6
. Then this result is assigned to b
. Finally, the result of that assignment expression (6
) is assigned to a
.
Incidentally, the following expression is also legal:
a = b = c = 3;
This expression assigns the value 3
to all three variables.
A compound assignment operator is an operator that performs a calculation and an assignment at the same time. All of Java's binary arithmetic operators (that is, the ones that work on two operands) have equivalent compound assignment operators, which Table 3-2 lists.
TABLE 3-2 Compound Assignment Operators
Operator |
Description |
|
Addition and assignment |
|
Subtraction and assignment |
|
Multiplication and assignment |
|
Division and assignment |
|
Remainder and assignment |
The statement
a += 10;
is equivalent to
a = a + 10;
Also, the statement
z *=2;
is equivalent to
z = z * 2;
int a = 2;
int b = 3;
a *= b + 1;
Is a
set to 7
or 8
?
In other words, is the third statement equivalent to
a = a * b + 1; // This would give 7 as the result
or
a = a * (b + 1); // This would give 8 as the result
At first glance, you might expect the answer to be 7
, because multiplication has a higher precedence than addition. But assignment has the lowest precedence of all, and the multiplication here is performed as part of the assignment. As a result, the addition is performed before the multiplication — and the answer is 8
. (Gotcha!)
Java's built-in operators are useful, but they don’t come anywhere near providing all the mathematical needs of most Java programmers. That’s where the Math
class comes in. It includes a bevy of built-in methods that perform a wide variety of mathematical calculations, from basic functions such as calculating an absolute value or a square root to trigonometry functions such as sin and cos (sine and cosine), to practical functions such as rounding numbers or generating random numbers.
I was going to make a joke here about how you’d have to take a math class to fully appreciate the Math
class; or how you'd better stay away from the Math
class if you didn’t do so well in math class; or how if you’re on the football team, maybe you can get someone to do the Math
class for you. But these jokes seemed too easy, so I decided not to make them.
double x = Math.sqrt(y);
The Math
class is contained in the java.lang
package, which is automatically available to all Java programs. As a result, you don't have to provide an import
statement to use the Math
class.
The following sections describe the most useful methods of the Math
class.
The Math
class defines two constants that are useful for many mathematical calculations. Table 3-3 lists these constants.
TABLE 3-3 Constants of the Math Class
Constant |
What It Is |
Value |
|
The constant pi (π), the ratio of a circle's radius and diameter |
3.141592653589793 |
|
The base of natural logarithms |
2.718281828459045 |
Note that these constants are only approximate values, because both π and e are irrational numbers.
The program shown in Listing 3-2 illustrates a typical use of the constant PI
. Here, the user is asked to enter the radius of a circle. Then the program calculates the area of the circle in line 11. (The parentheses aren't really required in the expression in this statement, but they help clarify that the expression is the Java equivalent to the formula for the area of a circle, πr2.)
Here’s the console output for a typical execution of this program, in which the user entered 5
as the radius of the circle:
Welcome to the circle area calculator.
Enter the radius of your circle: 5
The area is 78.53981633974483
LISTING 3-2 The Circle Area Calculator
import java.util.Scanner;
public class CircleAreaApp
{
static Scanner sc = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println(
"Welcome to the circle area calculator.");
System.out.print("Enter the radius of your circle: ");
double r = sc.nextDouble();
double area = Math.PI * (r * r);→11
System.out.println("The area is " + area);
}
}
Table 3-4 lists the basic mathematical functions that are provided by the Math
class. As you can see, you can use these functions to calculate such things as the absolute value of a number, the minimum and maximum of two values, square roots, powers, and logarithms.
TABLE 3-4 Commonly Used Mathematical Functions Provided by the Math Class
Method |
Explanation |
|
Returns the absolute value of the argument. The argument can be an |
|
Returns the cube root of the argument. The argument and return value are |
|
Returns e raised to the power of the argument. The argument and the return value are |
|
Returns the hypotenuse of a right triangle calculated according to the Pythagorean theorem — √ x2 + y2. The argument and the return values are |
|
Returns the natural logarithm (base e) of the argument. The argument and the return value are |
|
Returns the base 10 logarithm of the argument. The argument and the return value are |
|
Returns the larger of the two arguments. The arguments can be |
|
Returns the smaller of the two arguments. The arguments can be |
|
Returns the value of the first argument raised to the power of the second argument. Both arguments and the return value are |
|
Returns a random number that's greater than or equal to 0.0 but less than 1.0. This method doesn’t accept an argument, but the return value is a |
|
Returns a number that represents the sign of the argument: –1.0 if the argument is negative, 0.0 if the argument is zero, and 1.0 if the argument is positive. The argument can be a |
|
Returns the square root of the argument. The argument and return value are |
The program shown in Listing 3-3 demonstrates each of these methods except random
. When run, it produces output similar to this:
abs(b) = 50
cbrt(x) = 2.924017738212866
exp(y) = 54.598150033144236
hypot(y,z)= 5.0
log(y) = 1.0986122886681096
log10(y) = 0.47712125471966244
max(a, b) = 100
min(a, b) = -50
pow(a, c) = 1000000.0
random() = 0.8536014557793756
signum(b) = -1.0
sqrt(x) = 1.7320508075688772
You can use this output to get an idea of the values returned by these Math
class methods. You can see, for example, that the expression Math.sqrt(y)
returns a value of 5.0
when y
is 25.0
.
The following paragraphs point out a few interesting tidbits concerning these methods:
abs
and signnum
methods to force the sign of one variable to match the sign of another, like this:
int a = 27;
int b = -32;
a = Math.abs(a) * Math.signum(b); // a is now -27;
pow
method to square a number, like this:
double x = 4.0;
double y = Math.pow(x, 2); // a is now 16;
Simply multiplying the number by itself, however, is often just as easy and just as readable:
double x = 4.0;
double y = x * x; // a is now 16;
In the classic movie The Wizard of Oz, when the Wizard finally grants the Scarecrow his brains, the Scarecrow suddenly becomes intelligent and quotes the Pythagorean theorem, which is (coincidentally) used by the hypot
method of the Math
class. (Of course, he quotes it wrong. What the Scarecrow actually says in the movie is this: “The sum of the square root of any two sides of an isosceles triangle is equal to the square root of the remaining side.” Silly Scarecrow. He didn't need to know this to be smart.)
random
method call. The random
method is interesting enough that I describe it separately in the next section, “Creating random numbers.”LISTING 3-3 A Program That Uses the Mathematical Methods of the Math Class
public class MathFunctionsApp
{
public static void main(String[] args)
{
int a = 100;
int b = -50;
int c = 3;
double x = 25.0;
double y = 3.0;
double z = 4.0;
System.out.println("abs(b) = " + Math.abs(b));
System.out.println("cbrt(x) = " + Math.cbrt(x));
System.out.println("exp(y) = " + Math.exp(z));
System.out.println("hypot(y,z)= " + Math.hypot(y,z));
System.out.println("log(y) = " + Math.log(y));
System.out.println("log10(y) = " + Math.log10(y));
System.out.println("max(a, b) = " + Math.max(a, b));
System.out.println("min(a, b) = " + Math.min(a, b));
System.out.println("pow(a, c) = " + Math.pow(a, c));
System.out.println("random() = " + Math.random());
System.out.println("signum(b) = " + Math.signum(b));
System.out.println("sqrt(x) = " + Math.sqrt(y));
}
}
Sooner or later, you're going to want to write programs that play simple games. Almost all games have some element of chance built into them, so you need a way to create computer programs that don’t work exactly the same every time you run them. The easiest way to do that is to use the random
method of the Math
class, which Table 3-4 lists later in this section, along with the other basic mathematical functions of the Math
class.
The random
method returns a double
whose value is greater than or equal to 0.0 but less than 1.0. Within this range, the value returned by the random
method is different every time you call it and is essentially random.
The random
method generates a random double
value between 0.0 (inclusive, meaning that it could be 0.0) and 1.0 (exclusive, meaning that it can't be 1.0). Most computer applications that need random values, however, need random integers between some arbitrary low value (usually 1, but not always) and some arbitrary high value. A program that plays dice needs random numbers between 1 and 6, whereas a program that deals cards needs random numbers between 1 and 52 (53 if a joker is used).
As a result, you need a Java expression that converts the double
value returned by the random
function to an int
value within the range your program calls for. The following code shows how to do this, with the values set to 1
and 6
for a dice-playing game:
int low = 1; // the lowest value in the range
int high = 6; // the highest value in the range
int rnd = (int)(Math.random() * (high - low + 1)) + low;
This expression is a little complicated, so I show you how it's evaluated step by step:
Math.Random
method is called to get a random double value. This value is greater than 0.0 but less than 1.0.(int)
cast. Now you have an integer that's 0, 1, 2, 3, 4, or 5. (Remember that when you cast a double to an int
, any fractional part of the value is simply discarded. Because the number is less than 6.0, it never truncates to 6.0 when it is cast to an int
.)low
value in the range is added to the random number. Assuming that low
is 1
, the random number is now 1, 2, 3, 4, 5, or 6. That's just what you want: a random number between 1 and 6.To give you an idea of how this random-number calculation works, Listing 3-4 shows a program that places this calculation in a method called randomInt
and then calls it to simulate 100 dice rolls. The randomInt
method accepts two parameters representing the low and high ends of the range, and it returns a random integer within the range. In the main
method of this program, the randomInt
method is called 100 times, and each random number is printed by a call to System.out.print
.
The console output for this program looks something like this:
Here are 100 random rolls of the dice:
4 1 1 6 1 2 6 6 6 6 5 5 5 4 5 4 4 1 3 6 1 3 1 4 4 3 3 3 5 6 5 6 6 3 5 2 2 6 3 3
4 1 2 2 4 2 2 4 1 4 3 6 5 5 4 4 2 4 1 3 5 2 1 3 3 5 4 1 6 3 1 6 5 2 6 6 3 5 4 5
2 5 4 5 3 1 4 2 5 2 1 4 4 4 6 6 4 6 3 3
Every time you run this program, however, you see a different sequence of 100 numbers.
The program in Listing 3-4 uses several Java features that you haven't seen yet.
LISTING 3-4 Rolling the Dice
public class DiceApp
{
public static void main(String[] args)
{
int roll;
String msg = "Here are 100 random rolls of the dice:";
System.out.println(msg);
for (int i=0; i<100; i++)→8
{
roll = randomInt(1, 6);→10
System.out.print(roll + " ");→11
}
System.out.println();
}
public static int randomInt(int low, int high)→16
{
int result = (int)(Math.random()→18
* (high - low + 1)) + low;
return result;→20
}
}
The following paragraphs explain how the program works, but don’t worry if you don’t get all the elements in this program. The main thing to see is the expression that converts the random double
value returned by the Math.double
method to an integer.
for
statement causes the statements in its body (lines 10 and 11) to be executed 100 times. Don't worry about how this statement works for now; you find out about it in Book 2, Chapter 5.randomInt
method, specifying 1 and 6 as the range for the random integer to generate. The resulting random number is assigned to the roll
variable.System.out.print
method is used to print the random number followed by a space. Because this statement calls the print
method rather than the println
method, the random numbers are printed on the same line rather than on separate lines.randomInt
method indicates that the method returns an int
value and accepts two int
arguments: one named low
and the other named high
.double
value to an integer between low
and high
.return
statement sends the random number back to the statement that called the randomInt
method.The Math
class has four methods that round or truncate float
or double
values. Table 3-5 lists these methods. As you can see, each of these methods uses a different technique to calculate an integer
value that's near the double
or float
value passed as an argument. Note that even though all four of these methods round a floating-point value to an integer
value, only the round
method actually returns an integer
type (int
or long
, depending on whether the argument is a float
or a double
). The other methods return double
s that happen to be integer
values.
Listing 3-5 shows a program that uses each of the four methods to round three double
values: 29.4
, 93.5
, and -19.3
. Here's the output from this program:
round(x) = 29
round(y) = 94
round(z) = -19
ceil(x) = 30.0
ceil(y) = 94.0
ceil(z) = -19.0
floor(x) = 29.0
floor(y) = 93.0
floor(z) = -20.0
rint(x) = 29.0
rint(y) = 94.0
rint(z) = -19.0
TABLE 3-5 Rounding Functions Provided by the Math Class
Method |
Explanation |
|
Returns the smallest |
|
Returns the largest |
|
Returns the |
|
Returns the integer that is closest to the argument. If the argument is a |
Note that each of the four methods produces a different result for at least one of the values:
ceil
return 29.0
(or 29
) for the value 29.4
. ceil
returns 30.0
, which is the smallest integer that’s greater than 29.4
.floor
return 94.0
(or 94
) for the value 93.5
. floor
returns 93.0
because that’s the largest integer that’s less than 93.5. rint
returns 94.0
because it’s an even number, and 93.5 is midway between 93.0 and 94.0.floor
return -19.0
(or -19
) for -19.3
. floor
returns -20
because –20 is the largest integer that’s less than –19.3.LISTING 3-5 Program That Uses the Rounding Methods of the Math Class
public class RoundingApp
{
public static void main(String[] args)
{
double x = 29.4;
double y = 93.5;
double z = -19.3;
System.out.println("round(x) = " + Math.round(x));
System.out.println("round(y) = " + Math.round(y));
System.out.println("round(z) = " + Math.round(z));
System.out.println();
System.out.println("ceil(x) = " + Math.ceil(x));
System.out.println("ceil(y) = " + Math.ceil(y));
System.out.println("ceil(z) = " + Math.ceil(z));
System.out.println();
System.out.println("floor(x) = " + Math.floor(x));
System.out.println("floor(y) = " + Math.floor(y));
System.out.println("floor(z) = " + Math.floor(z));
System.out.println();
System.out.println("rint(x) = " + Math.rint(x));
System.out.println("rint(y) = " + Math.rint(y));
System.out.println("rint(z) = " + Math.rint(z));
}
}
Most of the programs you’ve seen so far have used the System.out.println
or System.out.print
method to print the values of variables that contain numbers. When you pass a numeric variable to one of these methods, the variable’s value is converted to a string before it’s printed. The exact format used to represent the value isn’t very pretty: Large values are printed without any commas, and all the decimal digits for double
or float
values are printed whether you want them to be or not.
In many cases, you want to format your numbers before you print them — to add commas to large values and limit the number of decimal places printed, for example. Or, if a number represents a monetary amount, you may want to add a dollar sign (or whatever currency symbol is appropriate for your locale). To do that, you can use the NumberFormat
class. Table 3-6 lists the NumberFormat
class methods.
TABLE 3-6 Methods of the NumberFormat Class
Method |
Explanation |
|
A static method that returns a |
|
A static method that returns a |
|
A static method that returns a |
|
Returns a string that contains the formatted number |
|
Sets the minimum number of digits to display to the right of the decimal point |
|
Sets the maximum number of digits to display to the right of the decimal point |
The procedure for using the NumberFormat
class to format numbers takes a little getting used to. First, you must call one of the static getXxxInstance
methods to create a NumberFormat
object that can format numbers in a particular way. Then, if you want, you can call the setMinimumFractionDigits
or setMaximumFractionDigits
method to set the number of decimal digits to be displayed. Finally, you call that object’s format
method to actually format a number.
Note that the NumberFormat
class is in the java.text
package, so you must include the following import
statement at the beginning of any class that uses NumberFormat
:
import java.text.NumberFormat;
Here’s an example that uses the NumberFormat
class to format a double
value as currency:
double salesTax = 2.425;
NumberFormat cf = NumberFormat.getCurrencyInstance();
System.out.println(cf.format(salesTax));
When you run this code, the following line is printed to the console:
$2.43
Note that the currency format rounds the value from 2.425
to 2.43
.
Here’s an example that formats a number by using the general number format, with exactly three decimal places:
double x = 19923.3288;
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(3);
nf.setMaximumFractionDigits(3);
System.out.println(nf.format(x));
When you run this code, the following line is printed:
19,923.329
Here the number is formatted with a comma and the value is rounded to three places.
Here’s an example that uses the percentage format:
double grade = .92;
NumberFormat pf = NumberFormat.getPercentInstance();
System.out.println(pf.format(grade));
When you run this code, the following line is printed:
92%
Believe it or not, computers — even the most powerful ones — have certain limitations when it comes to performing math calculations. These limitations are usually insignificant, but sometimes they sneak up and bite you. The following sections describe the things you need to watch out for when doing math in Java.
Okay, consider this (admittedly contrived) example:
int a = 1000000000;
System.out.println(a);
a += 1000000000;
System.out.println(a);
a += 1000000000;
System.out.println(a);
a += 1000000000;
System.out.println(a);
Here you expect the value of a
to get bigger after each addition. But here’s the output that’s displayed:
1000000000
2000000000
-1294967296
-294967296
The first addition seems to work, but after that, the number becomes negative! That’s because the value has reached the size limit of the int
data type. Unfortunately, Java doesn’t tell you that this error has happened. It simply crams the int
variable as full of bits as it can, discards whatever bits don’t fit, and hopes that you don’t notice. Because of the way int
stores negative values, large positive values suddenly become large negative values. This effect is called wrap around.
The moral of the story is that if you’re working with large integers, you should use long
rather than int
, because long
can store much larger numbers than int
. If your programs deal with numbers large enough to be a problem for long
, consider using floating-point types instead. As you see in the next section, floating-point types can handle even larger values than long
, and they let you know when you exceed their capacity.
Don’t believe me? Try running this code:
float x = 0.1f;
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(10);
System.out.println(nf.format(x));
The resulting output is this:
0.1000000015
Although 0.1000000015
is close to 0.1
, it isn’t exact.
According to the basic rules of mathematics, you can’t divide a number by zero. The reason is simple: Division is the inverse of multiplication — which means that if a * b = c
, it is also true that a = c / b
. If you were to allow b
to be zero, division would be meaningless, because any number times zero is zero. Therefore, both a
and c
would also have to be zero. In short, mathematicians solved this dilemma centuries ago by saying that division by zero is simply not allowed.
So what happens if you do attempt to divide a number by zero in a Java program? The answer depends on whether you’re dividing integers or floating-point numbers. If you’re dividing integers, the statement that attempts the division by zero chokes up what is called an exception, which is an impolite way of crashing the program. In Book 2, Chapter 8, you find out how to intercept this exception to allow your program to continue. In the meantime, any program you write that attempts an integer division by zero crashes.
If you try to divide a floating-point type by zero, the results are not so abrupt. Instead, Java assigns to the floating-point result one of the special values listed in Table 3-7. The following paragraphs explain how these special values are determined:
0.0
divided by 0.0
is positive infinity, as is -34.0
divided by -0.0
.-40.0
divided by 0.0
is negative infinity, as is 34.0
divided by 0.0
.NaN
), regardless of the signs.TABLE 3-7 Special Constants of the float and double Classes
Constant |
Meaning |
|
Positive infinity |
|
Negative infinity |
|
Not a number |
If you attempt to print a floating-point value that has one of these special values, Java converts the value to an appropriate string. Suppose that you execute the following statements:
double i = 50.0;
double j = 0.0;
double k = i / j;
System.out.println(k);
The resulting console output is
Infinity
If i
were -50.0
, the console would display -Infinity
, and if i
were zero, the console would display NaN
.
NaN
is not equal to itself, which can have some strange consequences. For example:
double x = Math.sqrt(-50); // Not a number
double y = x;
if (x == y)
System.out.println("x equals y");
Okay, I know that I jumped the gun here on the if
statement, because I don't cover if
statements until Book 2, Chapter 4. So just assume, for the sake of argument, that the if
statement tests whether the variable x
is equal to the variable y
. Because this test immediately follows an assignment statement that assigns the value of x
to y
, you can safely assume that x
equals y
, right?
Wrong. Because x
is NaN
, y
also is NaN
. NaN
is never considered to be equal to any other value, including another NaN
. Thus, the comparison in the if
statement fails.
double z = x - x; // not necessarily zero
Shouldn’t this statement always set z
to zero? Not if x
is NaN
. In that case, not a number minus not a number is still not a number.
NaN
. Infinity + 5, for example, still equals infinity, so Buzz Lightyear’s call “To infinity and beyond!” just isn’t going to happen. But infinity minus infinity gives you … NaN
.