8

The documentation states that the $end of the range is inclusive. And this is the case most of the time, but when both $end and $step are floats, the last value is missing. Why is that?

print_r(range(1, 13, 1));
print_r(range(1, 13, 0.1));
print_r(range(0.1, 1.3, 0.1));

Output:

Array
(
    [0] => 1
    [1] => 2
    // ...
    [11] => 12
    [12] => 13
)
Array
(
    [0] => 0.1
    [1] => 0.2
    // ...
    [119] => 12.9
    [120] => 13
)
Array
(
    [0] => 0.1
    [1] => 0.2
    // ...
    [10] => 1.1
    [11] => 1.2
    // 12 => 1.3 is missing
)
nCrazed
  • 1,025
  • 6
  • 20
  • Interesting. Maybe a bug in PHP 7? – Jeremy Harris Jan 19 '17 at 21:33
  • 2
    Floating point is approximate. When you increment by `0.1`, you won't always hit the end end exactly. – Barmar Jan 19 '17 at 21:35
  • 1
    Yes, seems to be PHP7 https://3v4l.org/kp1Fv – AbraCadaver Jan 19 '17 at 21:36
  • What happens if you run print_r((0.1 + ... + 0.1) == 1.3) - maybe it's due to precision in float? Replace == with < and > respectively, to see what happens... – Michael Lihs Jan 19 '17 at 21:37
  • But seems to be fine in a `for`: https://3v4l.org/IgD6t – AbraCadaver Jan 19 '17 at 21:38
  • It works as expected in PHP 5.5. But this type of error is to be expected with floating point, so it's not necessarily a bug, just a difference. – Barmar Jan 19 '17 at 21:38
  • 1
    Looks like a similar issue issue was reported and fixed for 7.0.5 https://bugs.php.net/bug.php?id=72017 – nCrazed Jan 19 '17 at 22:02
  • @Barmar Floats are exact, but they have limited range and precision, and you can't represent 0.1 in binary as a rational number. – Andrea Jan 22 '17 at 21:47
  • I understand that, I was being brief because it's just comment. http://stackoverflow.com/questions/588004/is-floating-point-math-broken explains things in more detail. – Barmar Jan 23 '17 at 01:02
  • Workaround: construct your second two ranges as `print_r(range(10, 130, 1));`, `print_r(range(10, 13, 1));` and then divide all their values by 10.0 and 10.0, respectively. – feedMe Feb 20 '17 at 09:34

1 Answers1

4

The range is inclusive; however, your assumptions about the numbers adding up are incorrect.

0.1 cannot be represented in binary with exact precision. When you use it in a calculation in php, you'll actually get a number that's a little higher or lower. Take a look at the following codepad:

http://codepad.org/MkoWgAA1

<?php

$sum = 1.0 + 0.1 + 0.1;

if ($sum > 1.2) {
  print("1.2 > 1.2");
} else if ($sum < 1.2) {
  print("1.2 < 1.2");
} else {
  print("1.2 == 1.2");
}

Output:

1.2 > 1.2
Sam Dufel
  • 17,560
  • 3
  • 48
  • 51
  • Interestingly enough this yields exactly the same results on all versions supported by [3v4l](https://3v4l.org/QYgXR) unlike my example which produces expected result on version 5.6 - 7.0.2 (as well as HHVM), but trips over floating point precisions on versions 7.0.3 - 7.1.1 – nCrazed Jan 20 '17 at 10:02