Math Utilities
Java supports integer and floating-point arithmetic directly in the language. Higher-level math operations are supported through the java.lang.Math class. As you may have seen by now, wrapper classes for primitive data types allow you to treat them as objects. Wrapper classes also hold some methods for basic conversions. Java provides the java.util.Random class for generating random numbers. First, a few words about built-in arithmetic in Java. 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 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 11-1.
Table 11-1. 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 (not a number) indicates the result of dividing zero by zero. This value has the special mathematical 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 is Java's math library. It holds a suite of static methods covering all of the usual mathematical operations like sin( ), cos( ), and sqrt( ). The Math class isn't very object-oriented (you can't create an instance of Math). Instead it's really just a convenient holder for static methods that are more like global functions. As we saw in , it's possible to use the new Java 5.0 static import functionality to import the names of static methods and constants like this directly into the scope of our class and use them as if they were defined there. Table 11-2 summarizes the methods in java.lang.Math.
Table 11-2. 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 or equal to a |
Math.cbrt(a) |
double |
Cube root of a |
Math.cos(a) |
double |
Cosine |
Math.cosh(a) |
double |
Hyperbolic 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.hypot(a,b) |
double |
Precision calculation of the sqrt( ) of a2 + b2 |
Math.log(a) |
double |
Natural logarithm of a |
Math.log10(a) |
double |
Log base 10 of a |
Math.max(a, b) |
int, long, float, double |
The value a or b closer to Long.MAX_VALUE |
Math.min(a, b) |
int, long, float, double |
The value a or b closer to Long.MIN_VALUE |
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.sinh(a) |
double |
Hyperbolic sine |
Math.sqrt(a) |
double |
Square root |
Math.tan(a) |
double |
Tangent |
Math.tanh(a) |
double |
Hyperbolic tangent |
log( ), pow( ), and sqrt( ) can throw a runtime 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 ); // 1.414... int bigger = Math.max( 3, 4 ); // 4 long one = Math.round( 1.125798 ); // 1
For convenience, Math also contains the static final double values E and PI:
double circumference = diameter * Math.PI;
The java.math Package
If the long and double types are not large or precise enough for you, the java.math package provides two classes, BigInteger and BigDecimal, that support arbitrary-precision numbers. These full-featured classes have a bevy of methods for performing arbitrary-precision math and precisely controlling rounding of remainders. In the following example, we use BigDecimal to add two very large numbers and then create a fraction with a 100-digit result:
long l1 = 9223372036854775807L; // Long.MAX_VALUE long l2 = 9223372036854775807L; System.out.println( l1 + l2 ); // -2 ! Not good. try { BigDecimal bd1 = new BigDecimal( "9223372036854775807" ); BigDecimal bd2 = new BigDecimal( 9223372036854775807L ); System.out.println( bd1.add( bd2 ) ); // 18446744073709551614 BigDecimal numerator = new BigDecimal(1); BigDecimal denominator = new BigDecimal(3); BigDecimal fraction = numerator.divide( denominator, 100, BigDecimal.ROUND_UP ); // 100 digit fraction = 0.333333 ... 3334 } catch (NumberFormatException nfe) { } catch (ArithmeticException ae) { }
If you implement cryptographic or scientific algorithms for fun, BigInteger is crucial. Other than that, you're not likely to need these classes.
Random Numbers
You can use the java.util.Random class to generate random values. It's a pseudorandom number generator that is initialized with a 48-bit seed.[*] Because it's a pseudorandom algorithm, you'll get the same series of values each time you use the same seed value. The default constructor uses the current time to produce a seed, but you can specify your own value in the constructor:
[*] The generator uses a linear congruential formula. See The Art of Computer Programming, Volume 2: Semi-numerical Algorithms by Donald Knuth (Oracle).
long seed = mySeed; Random rnums = new Random( seed );
Once you have a generator, you can ask for one or more random values of various types using the methods listed in Table 11-3.
Table 11-3. 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( ) |
inclusive to 1.0 exclusive |
nexTDouble( ) |
inclusive to 1.0 exclusive |
nextGaussian( ) |
Gaussian distributed double with mean 0.0 and standard deviation of 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. (Lots of natural phenomena follow a Gaussian distribution rather than a strictly uniform random one.) The static method Math.random( ) retrieves a random double value. This method initializes a private random number generator in the Math class the first time it's used, using the default Random constructor. Thus, every call to Math.random( ) corresponds to a call to nextdouble( ) on that random number generator.