Espresso: A Concentrated Introduction to Java


Numbers in Java

Summary: We introduce (or re-introduce) numbers in the Java programming language, focusing on a selection of useful operations.

Prerequisites: Basics of Java, Input and Output in Java, and Strings in Java.

Important Classes

Contents:

Primitive Types

Almost every modern programming language permits programmers to use variables of one or more numeric data types. Perhaps surprisingly, most also provide a variety of representations of numbers so that programmers can choose the ones that are most appropraite for the task at hand.

One important question is whether one accepts a fixed amount of memory for numeric values or prefers to permit memory to be allocated depending on the size of the number. If you limit yourself to a fixed amount of memory (as most languages do for the basic numeric types), one can only represent a limited number of values. If you permit memory to be allocated on the fly, you complicate operations (usually making them more costly in terms of time).

In Java, the primitive types long, int, and short each represent integers with a fixed amount of memory. The range of legal values for long is -263 to 263-1. The range of legal values for int is -231 to 231-1. The range of legal values for short is -215 to 215-1. You can represent constant values in each of these types by writing the digits of the value, potentially prefixed by a minus sign.

In Java, the primitive types double and float represent approximations of real numbers. The range of each is difficult to describe, particularly as they approximate different sizes of values differently. Beginning programmers should generally use double. You represent constant values of these types using the digits, including a possible decimal point. (Other notations are also available. We will introduce them as necessary.)

Note that we have referred to all of these types as primitive. This term suggests that they are the basic building blocks upon which other types in the language are built. It also suggests that they may have a lower-level implementation than do other types, which generally makes computation with primitive types more efficient.

Here are a few simple declarations of primitive numeric names and values.

int x = 5;
double pi_approx = 3.1415;

Arithmetic Operations

Java allows you to compute with the various primitive types of values. The binary arithmetic operations (addition, subtraction, multiplication, and division) are written with the natural symbol (+, -, *, and /) in standard infix form. (The term infix means that the operation is written between the two operands. It is contrasted with prefix, in which the operation appears before the operands, and postfix, in which the operation appears after the operands.)

For example, to add 2 to x and assign the result to y, you would write

y = x + 2;

Java understands precedence and associativity, so you can also combine operations in a single expression and have a predictable result, as in

pen.println(3 + 4 * 5); // prints 23
pen.println(3 - 1 - 1); // prints 1

Comparing Numbers

Numbers, like strings, are comparable. You can compare two numbers to determine whether the first is less than (<), less than or equal to (<=), equal to (==), greater than or equal to (>=), greater than (>) or not equal to (!=) another numeric values.

In all cases, the comparator goes between the new numbers, as in x < 5 or (y-j > 1.0).

It is generally considered a bad idea to compare two floating point approximations of real numbers for exact equality or inequality. Instead, one should take the absolute value of their difference and compare that to a relatively small value.

We will return to the comparison operations when we begin to work with conditionals.

Other Computations

What do you do if you want to perform more complex mathematical calculations, such as finding square roots? You use the useful class java.lang.Math. You should refer to the documentation for that class for more information.

Note that the calls to most of the methods in java.lang.Math take a slightly different form than you are used to. Rather than writing objectName.methodName(params), you write Math.methodName(params), as in

double root;
root = Math.sqrt(x);

Coercing Values

Most of the time, Java will permit you to use different numeric types and coerce a value to the appropriate type. For example, if you assign an integer to a double, it will convert the integer to the corresponding double (e.g., 5 to 5.0) before assigning. Similarly, if an operation has two different paramater types (e.g., you add an integer and a float), it will convert the less-general type to the more-general type.

You should be careful about such conversions, as they can lead to slight changes in your data (particularly as you use the approximation types). Strive to use the types you need and to stay within those types in thee expressions you write.

Numeric Classes

For each primitive numeric type, Java also has a corresponding class. These classes are java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, and java.lang.Double. All are based on the more general class java.lang.Number.

Each class also provides an appropriate constructor (e.g., the constructor for Integer accepts an int as a parameter) and a toString method that gives a representation of the value as a sequence of characters appropriate for output. Most also provide a constructor that takes a string as a parameter and parses it to extract the number.

For example,

Double d;
d = new Double(3.2);
Integer i;
i = new Integer("3123");

The string-based constructors are particularly useful for programs that must read numbers that the user types or includes in a text file.

pen.print("Enter grade: ");
pen.flush();
Integer grade = new Integer(i.readLine());

The general Number class (and therefore all the related classes) provides a number of conversion methods, including shortValue, intValue, longValue, floatValue, and doubleValue. Each of these methods returns a value of the specified type.

For example,

Double d;
d = new Double(3.14);
float f;
f = d.floatValue();

Big Numbers

Because some progams need values that go beyond the ranges of the primitive types (ranges that are duplicated by the corresponding number classes), Java also provides two kinds of arbitrary size numbers: java.math.BigDecimal and java.math.BigInteger.

These classes provide their own methods for the basic arithmetic and comparison operations. The basic operations are add, subtract, multiply, and divide. The operations are written in the object-oriented object dot method format. For example, you to multiply x by y and then add z, you might write:

BigInteger result, x, y, z;
...
result = x.multiply(y).subtract(z);

These methods are necessarily less efficient than those for the primitive classes. Nonethless, if you need to represent numbers beyond the normal ranges (or with greater precision, in the case of BigDecimal, they are excellent options.

History

Friday, 4 February 2005 [Samuel A. Rebelsky]

Monday, 7 February 2005 [Samuel A. Rebelsky]

Wednesday, 7 September 2005 [Samuel A. Rebelsky]

Wednesday, 1 February 2006 [Samuel A. Rebelsky]

Monday, 6 February 2006 [Samuel A. Rebelsky]


This page was generated by Siteweaver on Thu Mar 30 15:24:28 2006.
The source to the page was last modified on Mon Feb 6 14:23:17 2006.
This page may be found at http://www.cs.grinnell.edu/~rebelsky/Espresso/Readings/numbers.html.

You may wish to validate this page's HTML ; Valid CSS! ; Check with Bobby

Samuel A. Rebelsky
rebelsky@grinnell.edu