From: Dave Burt Date: 2006-03-22T20:13:50+09:00 Subject: Re: Round floats to N decimal places? Joel VanderWerf wrote: > Pat Maddox wrote: >> I'm doing some math that results in floats with ~10 decimal places, >> but I'd like to round them to 2 places. Is there a built in way of >> doing this? Right now I'm doing format("%0.2f", the_float).to_f, >> which seems to work fine but it seems like an ugly way of doing it. > ... > 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);