The trick is realizing that a float
can't accurately hold even all the integers in the range -3e+38 to 3e+38. The difference between "adjacent" float values depends on the magnitude: for float values close to 0, the difference between adjacent values; for very large values (positive or negative) the difference can be very large.
Basically a floating point number consists of:
- A sign - positive or negative
- A mantissa or significand (see comments below) - a string of binary digits, effectively
- An exponent - the number of binary digits to shift the mantissa left or right
The mantissa in a float
is 23 bits long, and the exponent is 8 bits - so you'll only ever get 23 (or 24 due to normalization) significant bits of information, but they could be shifted left a lot (to form a huge number) or right a lot (to form a tiny number). There are some other details around normalization which are relevant, but that's the basic idea.
See my .NET-oriented but still Java-relevant article on binary floating point for more information, along with one by Jeffrey Sax.