Tóm Tắt
Math Utilities
Java supports
integer and floating-point arithmetic
directly. Higher-level math operations are supported through the
java.lang.Math
class. Java provides wrapper classes for all primitive data types, so
you can treat them as objects if necessary. Java also provides the
java.util.Random
class for generating random numbers.
Java
handles errors in integer arithmetic by throwing an
ArithmeticException
:
int zero = 0; try { int i = 72 / zero; } catch ( ArithmeticException e ) { // division by zero }
To generate the error in this example, we created the intermediate
variable zero
. The compiler is somewhat crafty and
would have caught us if we had blatantly tried to perform a division
by a literal zero.
Floating-point arithmetic expressions,
on the other hand, don’t throw exceptions. Instead, they take
on the special out-of-range values shown in Table 9.3.
Table 9-3. Special Floating-Point Values
Value
Mathematical Representation
POSITIVE_INFINITY
1.0/0.0
NEGATIVE_INFINITY
-1.0/0.0
NaN
0.0/0.0
The following example generates an infinite result:
double zero = 0.0; double d = 1.0/zero; if ( d == Double.POSITIVE_INFINITY ) System.out.println( "Division by zero" );
The special value NaN
indicates the result is “not a number.” The value
NaN
has the special distinction of not being equal
to itself (NaN != NaN
evaluates to
true
). Use Float.isNaN( )
or
Double.isNaN( )
to test for
NaN
.
The java.lang.Math Class
The java.lang.Math
class
provides Java’s math library. All its methods are static and
used directly; you don’t have to (and you can’t)
instantiate a Math
object. We use this kind of
degenerate class when we really want methods to approximate standard
C-like functions. While this tactic defies the principles of
object-oriented design, it makes sense in this case, as it provides a
means of grouping some related utility functions in a single class.
Table 9.4 summarizes the
methods in
java.lang.Math
.
Table 9-4. Methods in java.lang.Math
Method
Argument Type(s)
Functionality
Math.abs(a)
int
, long
,
float
, double
Absolute value
Math.acos(a)
double
Arc cosine
Math.asin(a)
double
Arc sine
Math.atan(a)
double
Arc tangent
Math.atan2(a,b)
double
Angle part of rectangular-to-polar coordinate transform
Math.ceil(a)
double
Smallest whole number greater than orequal to a
Math.cos(a)
double
Cosine
Math.exp(a)
double
Math.E
to the power a
Math.floor(a)
double
Largest whole number less than or equal to a
Math.log(a)
double
Natural logarithm of a
Math.max(a, b)
int
, long
,
float
, double
Maximum
Math.min(a, b)
int
, long
,
float
, double
Minimum
Math.pow(a, b)
double
a
to the power b
Math.random( )
None
Random-number generator
Math.rint(a)
double
Converts double value to integral value in double format
Math.round(a)
float
, double
Rounds to whole number
Math.sin(a)
double
Sine
Math.sqrt(a)
double
Square root
Math.tan(a)
double
Tangent
log()
, pow()
, and
sqrt()
can throw an
ArithmeticException
. abs()
,
max( )
, and min( )
are
overloaded for all the scalar values,
int
, long
,
float
, or double
, and return
the corresponding type. Versions of Math.round( )
accept either float
or double
and return int
or long
,
respectively. The rest of the methods operate on and return
double
values:
double irrational = Math.sqrt( 2.0 ); int bigger = Math.max( 3, 4 ); long one = Math.round( 1.125798 );
For convenience,
Math
also contains the static final double values
E
and PI
:
double circumference = diameter * Math.PI;
The java.math Class
If a long
or a
double
just isn’t big enough for you, the
java.math
package
provides two classes,
BigInteger
and BigDecimal
, that
support arbitrary-precision numbers. These are
full-featured classes with a bevy of methods for performing
arbitrary-precision math. In the following example, we use
BigDecimal
to add two numbers:
try { BigDecimal twentyone = new BigDecimal("21"); BigDecimal seven = new BigDecimal("7"); BigDecimal sum = twentyone.add(seven); int answer= sum.intValue( ); // 28 } catch (NumberFormatException nfe) { } catch (ArithmeticException ae) { }
If you implement
cryptographic algorithms for fun,
BigInteger
is crucial. But other than that,
you’re not likely to need these classes.
Wrappers for Primitive Types
In languages like Smalltalk, numbers and
other simple types are objects, which makes for an elegant language
design, but has trade-offs in efficiency and complexity. By contrast,
there is a schism in the Java world between class types (i.e.,
objects) and primitive types (i.e., numbers, characters, and boolean
values). Java accepts this trade-off simply for efficiency reasons.
When you’re crunching numbers, you want your computations to be
lightweight; having to use objects for primitive types would
seriously affect performance. For the times you want to treat values
as objects, Java supplies a wrapper class for each of the primitive
types, as shown in Table 9.5.
Table 9-5. Primitive Type Wrappers
Primitive
Wrapper
void
java.lang.Void
boolean
java.lang.Boolean
char
java.lang.Character
byte
java.lang.Byte
short
java.lang.Short
int
java.lang.Integer
long
java.lang.Long
float
java.lang.Float
double
java.lang.Double
An instance of a wrapper class encapsulates a single value of its
corresponding type. It’s an immutable object that serves as a
container to hold the value and let us retrieve it later. You can
construct a wrapper object from a primitive value or from a
String
representation of the value. The following
statements are equivalent:
Float pi = new Float( 3.14 ); Float pi = new Float( "3.14" );
Wrapper
classes throw a NumberFormatException
when there
is an error in parsing a string:
try { Double bogus = new Double( "huh?" ); } catch ( NumberFormatException e ) { // bad number }
You should arrange to catch this exception if you want to deal with
it. Otherwise, since it’s a subclass of
RuntimeException
, it will propagate up the call
stack and cause a runtime error if not caught.
Sometimes you’ll use the wrapper classes simply to parse the
String
representation of a number:
String sheep = getParameter("sheep"); int n = new Integer( sheep ).intValue( );
Here
we are retrieving the value of the sheep
parameter. This value is returned as a String
, so
we need to convert it to a numeric value before we can use it. Every
wrapper class provides methods to get primitive values out of the
wrapper; we are using intValue( )
to retrieve an
int
out of Integer
. Since
parsing a String
representation of a number is
such a common thing to do, the Integer
and
Long
classes also provide the static methods
Integer.parseInt()
and Long.parseLong( )
that
read a String
and return the appropriate type. So
the second line in the previous example is equivalent to:
int n = Integer.parseInt( sheep );
Likewise, the Float
and Double
classes provide the static methods
Float.parseFloat()
and Double.parseDouble( )
, for parsing strings
into floating-point
primitives.
All wrappers provide access to their values in various forms. You can
retrieve scalar values with the methods
doubleValue()
, floatValue()
,
longValue( )
, and intValue( )
:
Double size = new Double ( 32.76 ); double d = size.doubleValue( ); // 32.76 float f = size.floatValue( ); // 32.76 long l = size.longValue( ); // 32 int i = size.intValue( ); // 32
This code is equivalent to casting the primitive double value to the
various types.
You also need a wrapper when you want to use a primitive value in a
situation that requires an object. As you’ll see shortly, a
Vector
is an extensible array of
Object
s. We can use wrappers to hold numbers in a
Vector
, along with other objects:
Vector myNumbers = new Vector( ); Integer thirtyThree = new Integer( 33 ); myNumbers.addElement( thirtyThree );
Here we have created an
Integer
wrapper object so that we can insert the
number into the Vector
, using addElement( )
. Later, when we are extracting
elements from the Vector
, we can recover the
int
value as follows:
Integer theNumber = (Integer)myNumbers.firstElement( ); int n = theNumber.intValue( ); // 33
Random Numbers
You can use
the java.util.Random
class to generate random
values. It’s a pseudo-random number generator that can be
initialized with a 48-bit seed.[ ] The default constructor uses the current time as a seed,
but if you want a repeatable sequence, specify your own seed with:
long seed = mySeed; Random rnums = new Random( seed );
This code creates a random-number generator. Once you have a
generator, you can ask for random values of various types using the
methods listed in Table 9.6.
Table 9-6. Random Number Methods
Method
Range
nextBoolean( )
true or false
nextInt( )
-2147483648 to 2147483647
nextInt(int n)
0 to (n – 1) inclusive
nextLong( )
-9223372036854775808 to 9223372036854775807
nextFloat( )
-1.0 to 1.0
nextDouble( )
-1.0 to 1.0
By default, the values are uniformly distributed. You can use the
nextGaussian( )
method to create
a Gaussian (bell curve) distribution of
double
values, with a mean of 0.0 and a
standard deviation of 1.0.
The static
method Math.random( )
retrieves a random double
value. This method
initializes a private
random-number generator in
the Math
class, using the default
Random
constructor. So every call to
Math.random( )
corresponds to a call to
nextDouble( )
on that random-number
generator.