Bug #17017

Range#max & Range#minmax incorrectly use Float end as max

Added by sambostock (Sam Bostock) 8 months ago. Updated 6 months ago.

Target version:
ruby -v:
ruby 2.8.0dev (2020-07-14T04:19:55Z master e60cd14d85) [x86_64-darwin17]


While continuing to add edge cases to Range#minmax specs, I discovered the following bug:

(1..3.1).to_a        == [1, 2, 3] # As expected

(1..3.1).to_a.max    == 3         # As expected
(1..3.1).to_a.minmax == [1, 3]    # As expected

(1..3.1).max    == 3.1            # Should be 3, as above
(1..3.1).minmax == [1, 3.1]       # Should be [1, 3], as above

One way to detect this scenario might be to do (whatever the C equivalent is of)

range_end.is_a?(Numeric)                      // Is this a numeric range?
  && (range_end - range_begin).modulo(1) == 0 // Can we reach the range_end using the standard step size (1)

As for how to handle it, a couple options come to mind:

  • We could error out and do something similar to what we do for exclusive ranges
raise TypeError, 'cannot exclude non Integer end value'
  • We might be able to calculate the range end by doing something like
num_steps = (range_end / range_beg).to_i - 1 # one fewer steps than would exceed the range_end
max = range_beg + num_steps                  # take that many steps all at once
  • We could delegate to super and enumerate the range to find the max
  • We could update the documentation to define the max for this case as the range_end, similarly to how the documentation for include? says it behaves like cover? for numeric ranges.

Also available in: Atom PDF