Espresso: A Concentrated Introduction to 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
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Number
java.math.BigDecimal
java.math.BigInteger
java.lang.Math
Contents:
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 -2^{63} to 2^{63}-1. The range of legal values for
int
is -2^{31} to 2^{31}-1. The range of
legal values for short
is -2^{15} to 2^{15}-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;
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
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.
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);
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.
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();
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.
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]
Math
operations.
Monday, 6 February 2006 [Samuel A. Rebelsky]
BigInteger
operations.
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 ; ; Check with Bobby