pharo icon indicating copy to clipboard operation
pharo copied to clipboard

Interval size error with Floating Point step

Open rjsargent opened this issue 1 year ago • 1 comments

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

rjsargent avatar Oct 17 '24 20:10 rjsargent

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

welcome[bot] avatar Oct 17 '24 20:10 welcome[bot]

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.

kasperosterbye avatar Mar 28 '25 15:03 kasperosterbye

Perhaps A should iterate B size times and get a consistent result.

rjsargent avatar Mar 28 '25 17:03 rjsargent