Algorithms and OOD (CSC 207 2014S) : Readings

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 and Strings in Java.

Important Classes

Primitive Types

Almost every modern programming language permits programmers to use variables of one or more numeric data types. Not so 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.

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.

Because java.lang.Math is primarily a utility class, when you call methods in that class, you typically write 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., one 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");

More recent versions of Java add the capability to automatically “box” and “unbox” numeric values - convert from the primitive representation to the object and back again.

Integer i = 3.14;
int j = i;

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.

Copyright (c) 2013-14 Samuel A. Rebelsky.

Creative Commons License

This work is licensed under a Creative Commons Attribution 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.