Thanks,
Pat
(the_float*100).round/100.0 is probably a bit faster... you might want
to check the benchmarks, though. Floats are inefficient in ruby, and the
string ops might actually be faster....
Oh what the heck, here's the benchmark, and the winner is... strings!
This might be good place to use a C extension, if you really need it to
be fast.
----
require 'benchmark'
n = 1000000
the_float = 1.0/7
raise unless ("%0.2f" % the_float).to_f == (the_float*100).round/100.0
Benchmark.bmbm(10) do |rpt|
rpt.report("float rounding") do
n.times {
("%0.2f" % the_float).to_f
}
end
rpt.report("string rounding") do
n.times {
(the_float*100).round/100.0
}
end
end
__END__
Output:
Rehearsal ---------------------------------------------------
float rounding 3.220000 0.000000 3.220000 ( 5.749314)
string rounding 2.240000 0.000000 2.240000 ( 4.452959)
------------------------------------------ total: 5.460000sec
user system total real
float rounding 3.170000 0.010000 3.180000 ( 6.379592)
string rounding 2.210000 0.000000 2.210000 ( 4.422063)
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
Oops. I got the benchmark labels backwards. Strings are slower. Here's
the correct code and output:
require 'benchmark'
n = 1000000
the_float = 1.0/7
raise unless ("%0.2f" % the_float).to_f == (the_float*100).round/100.0
Benchmark.bmbm(10) do |rpt|
rpt.report("float rounding") do
n.times {
(the_float*100).round/100.0
}
end
rpt.report("string rounding") do
n.times {
("%0.2f" % the_float).to_f
}
end
end
__END__
Output:
Rehearsal ---------------------------------------------------
float rounding 2.210000 0.000000 2.210000 ( 2.884535)
string rounding 3.210000 0.000000 3.210000 ( 6.516337)
------------------------------------------ total: 5.420000sec
user system total real
float rounding 2.190000 0.000000 2.190000 ( 4.398573)
string rounding 3.170000 0.010000 3.180000 ( 6.466687)
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);