Java Reference
In-Depth Information
loss of precision [JLS 5.1.2]. (The others are
long
to
float
and
long
to
double
.)
The initial value of
f
is so large that adding 50 to it and converting the result to a
float
produces
the same value as simply converting
f
to a
float
. In other words,
(float)2000000000 ==
2000000050
, so the expression
f < START + 50
is false before the loop body has executed even
once, and the loop body never gets a chance to run.
Fixing this program is as simple as changing the type of the loop variable from a
float
to an
int
.
This avoids all the imprecision associated with floatingpoint computation:
for (
int
i = START; i < START + 50; i++)
count++;
Without using a computer, how could you possibly have known that 2,000,000,050 has the same
float
representation as 2,000,000,000? The key is to observe that 2,000,000,000 has ten factors of
2: It begins with a 2 and has nine factors of 10, each of which is 5 x 2. This means that the binary
representation of 2,000,000,000 ends in ten 0s. The binary representation of 50 requires only six
bits, so adding 50 to 2,000,000,000 doesn't influence any bit higher than the sixth from the right. In
particular, the seventh and eighth bits from the right are still 0. Promoting this 31-bit
int
to a
float
with 24 bits of precision rounds between the seventh and eighth bits, which simply discards the
rightmost seven bits. The rightmost six bits are the only ones on which 2,000,000,000 and
2,000,000,050 differ, so their
float
representations are identical.
The moral of this puzzle is simple:
Do not use floating-point loop indices
, because it can lead to
unpredictable behavior. If you need a floating-point value in the body of a loop, take the
int
or
long
loop index and convert it to a
float
or
double
.
You may lose precision when converting an
int
or
long
to a
float
or a
long
to a
double
, but at least it will not affect the loop itself.
When
you use floating-point, use
double
rather than
float
unless you are certain that
float
provides
enough precision
and
you have a compelling performance need to use
float
. The times when it's
appropriate to use
float
rather than
double
are few and far between.
The lesson for language designers, yet again, is that silent loss of precision can be very confusing to
programmers. See
Puzzle 31
for further discussion.
< Day Day Up >
Search WWH ::
Custom Search