From: daniel@...42.com Date: 2019-07-26T13:22:33+00:00 Subject: [ruby-core:93931] [Ruby master Feature#16021] floor/ceil/round/truncate should accept a :step argument Issue #16021 has been updated by Dan0042 (Daniel DeLorme). shyouhei (Shyouhei Urabe) wrote: > Dan0042 (Daniel DeLorme) wrote: > > Equivalent to e.g. `((num / step.to_f).round * step)` > > > > ``` ruby > > 12.3456.floor(step: 0.2) #=> 12.2 > > ``` > > Can I ask you what do you expect for `12.3456.floor(step: 0.0002)` then? Good point, I see what you mean. I would expect 12.3456 but because of float imprecision we get 12.3454 using the above formula. Of course that's the gotcha with *any* float operations. Maybe I should have said *logically equivalent* to ((num / step.to_f).round * step) There are implementation workarounds, e.g. ``` ruby (12.3456 / 0.0002).next_float.floor * 0.0002 #=>12.345600000000001 (12.3456 / 0.0002) .round * 0.0002 #=>12.345600000000001 (12.3456 / 0.0002).prev_float.ceil * 0.0002 #=>12.345600000000001 ``` Or the new, magical `fix_float` method! :-) (half-jesting) ``` ruby class Float def fix_float(sensitivity=6) n = next_float return n if n.to_s.size < self.to_s.size - sensitivity p = prev_float return p if p.to_s.size < self.to_s.size - sensitivity return self end end (12.3456 / 0.0002) #=> 61727.99999999999 (12.3456 / 0.0002).fix_float #=> 61728.0 ((12.3456 / 0.0002).fix_float.floor * 0.0002).fix_float #=>12.3456 ``` ---------------------------------------- Feature #16021: floor/ceil/round/truncate should accept a :step argument https://bugs.ruby-lang.org/issues/16021#change-80060 * Author: Dan0042 (Daniel DeLorme) * Status: Feedback * Priority: Normal * Assignee: * Target version: ---------------------------------------- These rounding methods currently accept a number of (decimal) digits, but a more general mechanism would allow rounding to the nearest �, multiple of 5, etc. Equivalent to e.g. `((num / step.to_f).round * step)` ``` ruby 12.3456.floor(step: 0.2) #=> 12.2 12.3456.round(step: 0.2) #=> 12.4 12.3456.floor(step: 0.2) #=> 12.4 12.3456.floor(step: 0.2) #=> 12.2 ``` IMHO this should also apply to Time#floor/round/ceil ``` ruby Time.now.floor(step: 3600) #=> current hour Time.now.round(step: 3600) #=> nearest hour Time.now.ceil(step: 3600) #=> next hour ``` We can also consider that instead of `:step` , `:by` might be quite readable. ``` ruby 12.3456.round(by: 0.2) #=> 12.4 ``` -- https://bugs.ruby-lang.org/ Unsubscribe: