Project

General

Profile

Feature #16021

floor/ceil/round/truncate should accept a :step argument

Added by Dan0042 (Daniel DeLorme) about 2 months ago. Updated about 1 month ago.

Status:
Feedback
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:93917]

Description

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)

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

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 or :to might be quite readable.

12.3456.round(by: 0.2) #=> 12.4
12.3456.round(to: 0.2) #=> 12.4

History

Updated by shyouhei (Shyouhei Urabe) about 2 months ago

  • Status changed from Open to Feedback

Dan0042 (Daniel DeLorme) wrote:

Equivalent to e.g. ((num / step.to_f).round * step)

12.3456.floor(step: 0.2) #=> 12.2

Can I ask you what do you expect for 12.3456.floor(step: 0.0002) then?

Updated by shevegen (Robert A. Heiler) about 2 months ago

Hmm. I have mixed feelings about the proposal. I think in principle it
would be ok to add more flexibility as such (e. g. :step or :by, although
I think :step is a strange name). At the same time, though, this proposal
makes the use of .floor() etc... a bit more complicated. People have to
think more than before, such as by the example shown by shyouhei.

12.3456.floor(step: 0.0002)

versus

12.3456.floor(3)

(Not the same, I know, but my point is mostly that the second usage is
much easier to understand from a glance alone.)

I do not want to be discouraging but personally I more prefer to retain
the current way only.

Note that I have no really substantial opinion on the Time.now examples
given above - haven't thought about its usage implications yet. I mostly
refer to e. g. .floor() etc... on numbers.

Updated by Dan0042 (Daniel DeLorme) about 2 months ago

shyouhei (Shyouhei Urabe) wrote:

Dan0042 (Daniel DeLorme) wrote:

Equivalent to e.g. ((num / step.to_f).round * step)

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.

(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)

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

Updated by Dan0042 (Daniel DeLorme) about 2 months ago

shevegen (Robert A. Heiler) wrote:

(Not the same, I know, but my point is mostly that the second usage is
much easier to understand from a glance alone.)

Then what about making them equivalent so it's easier to compare which is more understandable.

12.3456.floor(step: 0.0002)

versus

(12.3456 / 0.0002).floor * 0.0002

IMHO the intent of the first one is obvious even without reading the floor documentation (but of course YMMV). If you think the second one is more understandable then my proposal has no leg to stand on.

Although as shyouhei pointed out, the pitfalls of float arithmetic mean that solving those pitfalls gives this proposal more value than just syntactic sugar alone.

#5

Updated by Dan0042 (Daniel DeLorme) about 1 month ago

  • Description updated (diff)

Also available in: Atom PDF