Interval size error with Floating Point step
Pharo v9 through v12 overstates the size of (-4 to: 4 by: 0.1) Bug description Since 0.1 is not exactly represented in FP, we should see only 80 elements in that interval. But, #size calculates as 81 rather than 80.
To Reproduce | elements | elements := OrderedCollection new. -4 to: 4 by: 0.1 do: [ :i | elements add: i]. elements size 80
| elements | elements := OrderedCollection new. (-4 to: 4 by: 0.1) do: [ :i | elements add: i]. elements size 81
Expected behavior #do: should enumerate the same 80 elements that #to:by:do: does.
Screenshots If applicable, add screenshots to help explain your problem.
Version information:
- OS: Windows
- Version: 10 Pro
- Pharo Version: 9 through 12, at least
Expected development cost Expected to be small
Thanks for opening your first issue! Please check the CONTRIBUTING documents for some tips about which information should be provided. You can find information of how to do a Pull Request here: https://github.com/pharo-project/pharo/wiki/Contribute-a-fix-to-Pharo
GitHub
Pharo is a dynamic reflective pure object-oriented language supporting live programming inspired by Smalltalk. - pharo-project/pharo
They use two different algorithms:
A) -4 to: 4 by: 0.1 do: uses a loop with N := -4. N := N + 0.1 in each iteration. Due to floating-point imprecision, this accumulates small errors.
B) (-4 to: 4 by: 0.1) do: uses N := -4 + index * 0.1, which avoids accumulating error and gives exactly 81 steps (ending at 4).
In A, the last number is 3.900000000000005, so the next (4.000000000000005) is above the upper limit and skipped. Result: 80 values.
In B, -4 + 80 * 0.1 = 4.0, so the 81st value is exactly 4.0 and included.
B is more precise because it uses multiplication instead of repeated addition. In the past, multiplication was slower, but probably not today.
Also, try -4 to: 4 by: (1/10) — this uses Fraction, which gives mathematically perfect results: 80th value = 39/10, 81st = 40/10 = 4.
Is this a bug? I’d call it a subtle mismatch, not a bug. But it may surprise users.
Perhaps A should iterate B size times and get a consistent result.