Joel said:
...
This might be good place to use a C extension, if you really need it to
be fast.
Facets adds Numeric#round_at(d) and round_to(n).
http://facets.rubyforge.org/doc/api/classes/Float.html
Why not alter Ruby's core Numeric#round to accept an extra parameter, with
the same function as Facets' round_at(d)? I've attached a patch (untested)
below.
It seems to me it's fully backwards-compatible, hardly slower, and not at
all confusing. Round is a good name for this function, and it isn't
incongruent with the existing function of that method.
Cheers,
Dave
Untested patch against 1.8.2:
--- numeric.c~ Wed Mar 22 19:41:54 2006
+++ numeric.c Wed Mar 22 22:01:47 2006
@@ -1274,17 +1274,35 @@
flo_round(num)
VALUE num;
{
+ return flo_round2(0, NULL, num);
+}
+
+static VALUE
+flo_round2(argc, argv, num)
+ int argc;
+ VALUE *argv;
+ VALUE num;
+{
double f = RFLOAT(num)->value;
long val;
+ int dp;
+ double x;
- if (f > 0.0) f = floor(f+0.5);
- if (f < 0.0) f = ceil(f-0.5);
+ if (argc) {
+ rb_scan_args(argc, argv, "01", &dp);
+ x = pow(10.0, (double)dp);
+ return rb_float_new((int)(num * x) / x);
+ }
+ else {
+ if (f > 0.0) f = floor(f+0.5);
+ if (f < 0.0) f = ceil(f-0.5);
- if (!FIXABLE(f)) {
- return rb_dbl2big(f);
+ if (!FIXABLE(f)) {
+ return rb_dbl2big(f);
+ }
+ val = f;
+ return LONG2FIX(val);
}
- val = f;
- return LONG2FIX(val);
}
/*
@@ -1372,6 +1390,15 @@
return flo_round(rb_Float(num));
}
+static VALUE
+num_round2(argc, argv, num)
+ int argc,
+ VALUE *argv,
+ VALUE num;
+{
+ return flo_round(argc, argv, rb_Float(num));
+}
+
/*
* call-seq:
* num.truncate => integer
@@ -2799,7 +2826,7 @@
rb_define_method(rb_cNumeric, "floor", num_floor, 0);
rb_define_method(rb_cNumeric, "ceil", num_ceil, 0);
- rb_define_method(rb_cNumeric, "round", num_round, 0);
+ rb_define_method(rb_cNumeric, "round", num_round2, -1);
rb_define_method(rb_cNumeric, "truncate", num_truncate, 0);
rb_define_method(rb_cNumeric, "step", num_step, -1);
@@ -2819,7 +2846,6 @@
rb_define_method(rb_cInteger, "to_int", int_to_i, 0);
rb_define_method(rb_cInteger, "floor", int_to_i, 0);
rb_define_method(rb_cInteger, "ceil", int_to_i, 0);
- rb_define_method(rb_cInteger, "round", int_to_i, 0);
rb_define_method(rb_cInteger, "truncate", int_to_i, 0);
rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);
@@ -2913,7 +2939,7 @@
rb_define_method(rb_cFloat, "to_int", flo_truncate, 0);
rb_define_method(rb_cFloat, "floor", flo_floor, 0);
rb_define_method(rb_cFloat, "ceil", flo_ceil, 0);
- rb_define_method(rb_cFloat, "round", flo_round, 0);
+ rb_define_method(rb_cFloat, "round", flo_round2, -1);
rb_define_method(rb_cFloat, "truncate", flo_truncate, 0);
rb_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);