Floating point primitives in Java
Java has two built-in floating point data types: float and
double. Essentially, these represent and allow calculations on real numbers
(i.e. whole numbers or otherwise) with a range and precision that
are suitable for most everyday calculations:
Data type | Bytes used | Significant figures (decimal) | Range |
float | 4 | 7 | approx 38 places before or after the decimal point |
double | 8 | 15 | approx 300 places before or after the decimal point |
In most cases, this boils down to the following:
For performing calculations on non-whole numbers in most everyday applications,
use the double type.
Basic operations
So in our program, we may then perform basic calculations as follows—
essentially "as you'd expect":
double a = 7.45;
double b = 1.52;
double sum = a + b;
double multiplied = a * b;
The four basic operators +, -, * and /
essentially do "what you'd expect".
How to compute powers
If you're used to programming in BASIC, you may be used to using the hat operator
(^) to comput powers. In Java, as in various languages, the ^ operator actually
performs an Exclusive OR (XOR). To compute a power in Java, there are two main
options. Firstly, if easily possible, replace the power by a multimplication: for example,
to square a number, multiply itself by itself; to cube a number, multiply itself
by itself twice etc:
double xSquared = x * x;
double xCubed = xSquared * x;
double xQuadrupled = xSquared * xSquared;
Where this isn't possible or feasible (e.g. the power is large or not a whole
number), then use the Math.pow() method from the java.util.Math class.
For example, to calculate 401.5 and x2y:
double result = Math.pow(40, 1.5);
double result2 = Math.pow(x, 2*y);
The Math.pow() method is typically around 300-600 times slower than a
mutliplication, but in many applications this doesn't matter: the computation still
takes a tiny fraction of a millisecond.
Other mathematical operations
Like Math.pow(), the java.util.Math class contains various
other static methods for performing common operations such as trigonometric functions
and calculating logarithms.
Why not use float?
You may be wondering what I have against the poor float type and
why I recommend always using double rather than float.
Well essentially because:
- on most processors, most operations take the same amount of time
on floats as on doubles;
- doubles offer far better precision than floats;
the 15-digit precision of dobules is practically always sufficient,
whereas the 7-digit precision of floats may well be insufficient
for various "everyday" applications;
- nowadays, you can usually spare the extra 4 bytes required to store a
double.
The float type offers poor precision and I would posit that
the motivation for using it is largely historic, stemming from a time
when memory was much more scarce and processor operations were genuinely faster on
4-byte numbers compared to 8-byte numbers. These days, even if you have to store
millions of numbers in memory, you may as well double your memory capacity for a few
dollars rather than halving the storage space of each number. And, with the exception
of division, processor calculation units are so fast that, either on floats or
doubles, the actual speed of the operation is determined by the
length of a clock cycle rather than the number of digits1.
Next: other mathematical operations
On the next page, we give an overview of the
java.util.Math class, which provides methods for performing various
common mathematical operations.
Or put more simply: the
calculation unit of the processor can manipulate an 8-byte number faster than the
result can be processed, so that there is no overall saving in using a 4-byte number.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.