Team LiB
Previous Section Next Section

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 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 generator2 = new;
// 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));

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.

    Team LiB
    Previous Section Next Section