5.3. Numbers and Math
Java provides the
byte, short,
int, long,
float, and double
primitive types for representing
numbers. The java.lang
package includes the corresponding
Byte, Short,
Integer, Long,
Float, and Double classes, each
of which is a subclass of Number. These classes
can be useful as object wrappers around their primitive types, and
they also define some useful constants:
// Integral range constants: Integer, Long, and Character also define these
Byte.MIN_VALUE // The smallest (most negative) byte value
Byte.MAX_VALUE // The largest byte value
Short.MIN_VALUE // The most negative short value
Short.MAX_VALUE // The largest short value
// Floating-point range constants: Double also defines these
Float.MIN_VALUE // Smallest (closest to zero) positive float value
Float.MAX_VALUE // Largest positive float value
// Other useful constants
Math.PI // 3.14159265358979323846
Math.E // 2.7182818284590452354
5.3.1. Mathematical Functions
The
Math class
defines a number of methods that provide trigonometric, logarithmic,
exponential, and rounding operations, among others. This class is
primarily useful with floating-point values. For the trigonometric
functions, angles are expressed in radians. The logarithm and
exponentiation functions are base e, not base
10. Here are some examples:
double d = Math.toRadians(27); // Convert 27 degrees to radians
d = Math.cos(d); // Take the cosine
d = Math.sqrt(d); // Take the square root
d = Math.log(d); // Take the natural logarithm
d = Math.exp(d); // Do the inverse: e to the power d
d = Math.pow(10, d); // Raise 10 to this power
d = Math.atan(d); // Compute the arc tangent
d = Math.toDegrees(d); // Convert back to degrees
double up = Math.ceil(d); // Round to ceiling
double down = Math.floor(d); // Round to floor
long nearest = Math.round(d); // Round to nearest
In Java 5.0, several new functions have been
added to the Math class, including the following:
double d = 27;
d = Math.cbrt(d); // cube root
d = Math.log10(d); // base-10 logarithm
d = Math.sinh(d); // hyperbolic sine. Also cosh() and tanh()
d = Math.hypot(3, 4); // Hypotenuse
5.3.2. Random Numbers
The
Math class also defines a rudimentary method for
generating pseudo-random numbers, but the
java.util.Random class is more flexible. If you need
very random pseudo-random numbers, you can use
the java.security.SecureRandom
class:
// A simple random number
double r = Math.random(); // Returns d such that: 0.0 <= d < 1.0
// Create a new Random object, seeding with the current time
java.util.Random generator = new java.util.Random(System.currentTimeMillis());
double d = generator.nextDouble(); // 0.0 <= d < 1.0
float f = generator.nextFloat(); // 0.0 <= f < 1.0
long l = generator.nextLong(); // Chosen from the entire range of long
int i = generator.nextInt(); // Chosen from the entire range of int
i = generator.nextInt(limit); // 0 <= i < limit (Java 1.2 and later)
boolean b = generator.nextBoolean(); // true or false (Java 1.2 and later)
d = generator.nextGaussian(); // Mean value: 0.0; std. deviation: 1.0
byte[] randomBytes = new byte[128];
generator.nextBytes(randomBytes); // Fill in array with random bytes
// For cryptographic strength random numbers, use the SecureRandom subclass
java.security.SecureRandom generator2 = new java.security.SecureRandom();
// Have the generator generate its own 16-byte seed; takes a *long* time
generator2.setSeed(generator2.generateSeed(16)); // Extra random 16-byte seed
// Then use SecureRandom like any other Random object
generator2.nextBytes(randomBytes); // Generate more random bytes
5.3.3. Big Numbers
The
java.math package contains the
BigInteger and BigDecimal classes.
These classes allow you to work with arbitrary-size and
arbitrary-precision integers and floating-point values. For example:
import java.math.*;
// Compute the factorial of 1000
BigInteger total = BigInteger.valueOf(1);
for(int i = 2; i <= 1000; i++)
total = total.multiply(BigInteger.valueOf(i));
System.out.println(total.toString());
In Java 1.4,
BigInteger has a method
to randomly generate large prime numbers, which is useful in many
cryptographic applications:
BigInteger prime =
BigInteger.probablePrime(1024, // 1024 bits long
generator2); // Source of randomness. From above.
The BigDecimal class has been overhauled in Java 5.0 and
is much more usable in this release. In addition to its utility for
representing very large or very precise floating point numbers, it is
also useful for financial calculations because it relies on a
decimal representation
of fractions rather than a binary representation.
float and double values cannot
precisely represent a number as simple as 0.1, and this can cause
rounding errors that are often unacceptable when representing
monetary values. BigDecimal and its associated
MathContext and RoundingMode types
provide a solution. For example:
// Compute monthly interest payments on a loan
public static BigDecimal monthlyPayment(int amount, // amount of loan
int years, // term in years
double apr) // annual interest %
{
// Convert the loan amount to a BigDecimal
BigDecimal principal = new BigDecimal(amount);
// Convert term of loan in years to number of monthly payments
int payments=years*12;
// Convert interest from annual percent to a monthly decimal
BigDecimal interest = BigDecimal.valueOf(apr);
interest = interest.divide(new BigDecimal(100)); // as fraction
interest = interest.divide(new BigDecimal(12)); // monthly
// The monthly payment computation
BigDecimal x = interest.add(BigDecimal.ONE).pow(payments);
BigDecimal y = principal.multiply(interest).multiply(x);
BigDecimal monthly = y.divide(x.subtract(BigDecimal.ONE),
MathContext.DECIMAL64); // note context
// Convert to two decimal places
monthly = monthly.setScale(2, RoundingMode.HALF_EVEN);
return monthly;
}
5.3.4. Converting Numbers from and to Strings
A Java program that operates on
numbers must get its input values from somewhere. Often, such a
program reads a textual representation of a number and must convert
it to a numeric representation. The various Number
subclasses define useful conversion methods:
String s = "-42";
byte b = Byte.parseByte(s); // s as a byte
short sh = Short.parseShort(s); // s as a short
int i = Integer.parseInt(s); // s as an int
long l = Long.parseLong(s); // s as a long
float f = Float.parseFloat(s); // s as a float (Java 1.2 and later)
f = Float.valueOf(s).floatValue(); // s as a float (prior to Java 1.2)
double d = Double.parseDouble(s); // s as a double (Java 1.2 and later)
d = Double.valueOf(s).doubleValue(); // s as a double (prior to Java 1.2)
// The integer conversion routines handle numbers in other bases
byte b = Byte.parseByte("1011", 2); // 1011 in binary is 11 in decimal
short sh = Short.parseShort("ff", 16); // ff in base 16 is 255 in decimal
// The valueOf() method can handle arbitrary bases between 2 and 36
int i = Integer.valueOf("egg", 17).intValue(); // Base 17!
// The decode() method handles octal, decimal, or hexadecimal, depending
// on the numeric prefix of the string
short sh = Short.decode("0377").byteValue(); // Leading 0 means base 8
int i = Integer.decode("0xff").shortValue(); // Leading 0x means base 16
long l = Long.decode("255").intValue(); // Other numbers mean base 10
// Integer class can convert numbers to strings
String decimal = Integer.toString(42);
String binary = Integer.toBinaryString(42);
String octal = Integer.toOctalString(42);
String hex = Integer.toHexString(42);
String base36 = Integer.toString(42, 36);
5.3.5. Formatting Numbers
The
printf()
and format( )
methods of Java 5.0 described earlier in this chapter work well for
formatting numbers. The %d format specifier is for
formatting integers in decimal format:
// Format int, long and BigInteger to the string "1 10 100"
String s = String.format("%d %d %d", 1, 10L, BigInteger.TEN.pow(2));
// Add thousands separators
s = String.format("%,d", Integer.MAX_VALUE); // "2,147,483,647"
// Output value right-justified in a field 8 characters wide
s = String.format("%8d", 123); // " 123"
// Pad on the left with zeros to make 5 digits total
s = String.format("%05d", 123); // "00123"
Floating-point numbers can be
formatted using %f, %e, or
%g format specifiers, which differ in whether and
when exponential notation is used:
double x = 1.234E9; // (1.234 billion)
// returns "1234000000.000000 1.234000e+09 1.234000e+09 1234.000000"
s = String.format("%f %e %g %g", x, x, x, x/1e6);
You'll notice that the numbers above are all
formatted with six digits following the decimal point. This default
can be altered by specifying a precision in the
format string:
// display a BigDecimal with 2 significant digits
s = String.format("%.2f", new BigDecimal("1.234")); // "1.23"
Other flags can be applied to floating-point conversions as well. The
following code formats a column of numbers right-justified within a
field 10 characters wide. Each number has two digits following the
decimal place and includes thousands separators when necessary.
Negative values are formatted in parentheses, a common formatting
convention in accounting.
// A column of 4 numbers. %n is newline.
s = String.format("%(,10.2f%n%(,10.2f%n%(,10.2f%n%(,10.2f%n",
BigDecimal.TEN, // 10.00
BigDecimal.TEN.movePointRight(3), // 10,000.00
BigDecimal.TEN.movePointLeft(3), // 0.01
BigDecimal.TEN.negate()); // (10.00)
See java.util.Formatter in the reference section
for complete details on supported format specifiers and formatting
options.
Prior to Java 5.0, numbers can be formatted using the
java.text.NumberFormat class:
import java.text.*;
// Use NumberFormat to format and parse numbers for the current locale
NumberFormat nf = NumberFormat.getNumberInstance(); // Get a NumberFormat
System.out.println(nf.format(9876543.21)); // Format number for current locale
try {
Number n = nf.parse("1.234.567,89"); // Parse strings according to locale
} catch (ParseException e) { /* Handle exception */ }
// Monetary values are sometimes formatted differently than other numbers
NumberFormat moneyFmt = NumberFormat.getCurrencyInstance();
System.out.println(moneyFmt.format(1234.56)); // Prints $1,234.56 in U.S.
|