Because not only float math is flawed, sometimes its representation is flawed too - and that's the case here.
You don't actually get 0.1, 0.2, ... - and that's quite easy to check:
$start = 0;
$stop = 1;
$step = ($stop - $start)/10;
$i = $start + $step;
while ($i < $stop) {
print(number_format($i, 32) . "<br />");
$i += $step;
}
The only difference here, as you see, is that echo
replaced with number_format
call. But the results are drastically different:
0.10000000000000000555111512312578
0.20000000000000001110223024625157
0.30000000000000004440892098500626
0.40000000000000002220446049250313
0.50000000000000000000000000000000
0.59999999999999997779553950749687
0.69999999999999995559107901499374
0.79999999999999993338661852249061
0.89999999999999991118215802998748
0.99999999999999988897769753748435
See? Only one time it was 0.5
actually - because that number can be stored in a float container. All the others were only approximations.
How to solve this? Well, one radical approach is using not floats, but integers in similar situations. It's easy to notice that have you done it this way...
$start = 0;
$stop = 10;
$step = (int)(($stop - $start) / 10);
$i = $start + $step;
while ($i < $stop) {
print(number_format($i, 32) . "<br />");
$i += $step;
}
... it would work ok:
Alternatively, you can use number_format
to convert the float into some string, then compare this string with preformatted float. Like this:
$start = 0;
$stop = 1;
$step = ($stop - $start) / 10;
$i = $start + $step;
while (number_format($i, 1) !== number_format($stop, 1)) {
print(number_format($i, 32) . "\n");
$i += $step;
}