The key word is "exactly".
float
can represent 1e8
, even exactly, unless you have a freak float
type. But that doesn't mean it can represent all smaller values exactly, for example, usually 2^25+1 = 33554433
, which needs 26 bits of precision, cannot be exactly represented in float
(usually, that has 23+1 bits of precision), nor can 2^25-1 = 33554431
, which needs 25 bits of precision.
Both of these numbers are then represented as 2^25 = 33554432
, and then
33554432.0f - 1 == 33554432.0f
will loop. (You will hit a loop earlier, but that one has a nice decimal representation ;)
In integer arithmetic, you have x - 1 != x
for all x
, but not in floating point arithmetic.
Note that the loop might also finish even if float
has only the usual 23+1 bits of precision, since the standard allows floating point computations to be carried out at a greater precision than the type has, and if the computation is performed at sufficiently greater precision (e.g. the usual double
with 52+1 bits), every subtraction will change x
.