Project

General

Profile

Actions

Feature #12244

open

Add a way to `integer - integer % num`

Feature #12244: Add a way to `integer - integer % num`

Added by naruse (Yui NARUSE) over 9 years ago. Updated over 1 year ago.

Status:
Assigned
Target version:
-
[ruby-core:74786]

Description

We sometimes calculates integer - integer % num.

For example time series events into time partitions, we write code like

event # {time: 1459580435, name: "hoge", text: "Rawr!"} partition = event[:time] - event[:time] % num chunk = get_chunk(partition) chunk.write event 

https://twitter.com/tagomoris/status/715814050534461440
https://twitter.com/tagomoris/status/715814961260457985

The name is always issue.
There are some suggestions likes Integer#adjust](https://twitter.com/cocoatomo/status/716088708655489024).

kosaki says Excel's FLOOR() function is FLOOR(number, significance).
Therefore Ruby should be Integer#floor(digits=1, significance: nil).
kosaki agrees this.

I checked the speed of a half baked implementation..., but it's 10x slow...

% time ./miniruby -e'i=10000000;while i>0;i-=1;1459497599.floor(significance: 3600);end' ./miniruby 6.58s user 0.02s system 99% cpu 6.596 total #3 1459604131 22:35:31 naruse@windy:~/obj/ruby % time ./miniruby -e'i=10000000;while i>0;i-=1;t=1459497599;t-t%3600;end' ./miniruby -e'i=10000000;while i>0;i-=1;t=1459497599;t-t%3600;end' 0.52s user 0.00s system 99% cpu 0.520 total 
diff --git a/numeric.c b/numeric.c index 37217a1..f6acfe3 100644 --- a/numeric.c +++ b/numeric.c @@ -4123,6 +4123,42 @@ int_dotimes(VALUE num)   /* * call-seq: + * int.floor([ndigits]) -> integer or float + * + * Rounds +int+ to a given precision in decimal digits (default 0 digits). + * + * Precision may be negative. Returns a floating point number when +ndigits+ + * is positive, +self+ for zero, and round down for negative. + * + * 1.round #=> 1 + * 1.round(2) #=> 1.0 + * 15.round(-1) #=> 20 + */ + +static VALUE +int_floor(int argc, VALUE* argv, VALUE num) +{ + static ID keyword_ids[1]; + VALUE kwargs[1], ndigits, opt; + if (!keyword_ids[0]) { + CONST_ID(keyword_ids[0], "significance"); + } + + rb_scan_args(argc, argv, "01:", &ndigits, &opt); + if (!NIL_P(opt)) { + VALUE factor; + long a, b; + rb_get_kwargs(opt, keyword_ids, 0, 1, kwargs); + factor = kwargs[0]; + a = FIX2LONG(num); + b = FIX2LONG(factor); + return LONG2FIX(a - a % b); + } + return Qnil; +} + +/* + * call-seq:  * int.round([ndigits]) -> integer or float * * Rounds +int+ to a given precision in decimal digits (default 0 digits). @@ -4321,7 +4357,7 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "to_i", int_to_i, 0); rb_define_method(rb_cInteger, "to_int", int_to_i, 0); rb_define_method(rb_cInteger, "to_f", int_to_f, 0); - rb_define_method(rb_cInteger, "floor", int_to_i, 0); + rb_define_method(rb_cInteger, "floor", int_floor, -1);  rb_define_method(rb_cInteger, "ceil", int_to_i, 0); rb_define_method(rb_cInteger, "truncate", int_to_i, 0); rb_define_method(rb_cInteger, "round", int_round, -1); 

Updated by naruse (Yui NARUSE) over 9 years ago Actions #1 [ruby-core:74790]

  • Description updated (diff)

Updated by naruse (Yui NARUSE) over 9 years ago Actions #2 [ruby-core:74791]

Why this new method is too slow seems because of keyword argument.

Updated by matz (Yukihiro Matsumoto) over 9 years ago Actions #3 [ruby-core:75539]

The proposed behavior seems reasonable for me.
The only concern is performance. We need measurement.

Matz.

Updated by hsbt (Hiroshi SHIBATA) over 1 year ago Actions #4

  • Status changed from Open to Assigned
Actions

Also available in: PDF Atom