From 75c42535c9e49a3afae910d533874933558857ed Mon Sep 17 00:00:00 2001 From: marcandre Date: Sun, 4 Sep 2011 20:14:29 +0000 Subject: * numeric.c (flo_round): Make Float#round round big values [bug #5272] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33186 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ numeric.c | 50 ++++++++++++++++---------------------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 89e33de2d4..984e26779b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Sep 5 05:13:22 2011 Marc-Andre Lafortune + + * numeric.c (flo_round): Make Float#round round big values [bug + #5272] + Mon Sep 5 04:28:25 2011 Marc-Andre Lafortune * numeric.c (int_round): Integer#round always returns an Integer [Bug diff --git a/numeric.c b/numeric.c index 10c153ebe5..d3977e44ee 100644 --- a/numeric.c +++ b/numeric.c @@ -1494,6 +1494,9 @@ int_round_0(VALUE num, int ndigits) return n; } +static VALUE +flo_truncate(VALUE num); + /* * call-seq: * flt.round([ndigits]) -> integer or float @@ -1531,13 +1534,18 @@ flo_round(int argc, VALUE *argv, VALUE num) double number, f; int ndigits = 0; int binexp; - long val; enum {float_dig = DBL_DIG+2}; if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) { ndigits = NUM2INT(nd); } + if (ndigits < 0) { + return int_round_0(flo_truncate(num), ndigits); + } number = RFLOAT_VALUE(num); + if (ndigits == 0) { + return dbl2ival(number); + } frexp(number, &binexp); /* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}", @@ -1557,41 +1565,15 @@ flo_round(int argc, VALUE *argv, VALUE num) So if ndigits + binexp/(4 or 3) >= float_dig, the result is number If ndigits + binexp/(3 or 4) < 0 the result is 0 */ - if (isinf(number) || isnan(number)) { - /* Do nothing */ - } - else if ((long)ndigits * (4 - (binexp > 0)) + binexp < 0) { - number = 0; - } - else if (((long)ndigits - float_dig) * (3 + (binexp > 0)) + binexp < 0) { - f = pow(10, abs(ndigits)); - if (ndigits < 0) { - double absnum = fabs(number); - if (absnum < f) return INT2FIX(0); - if (!FIXABLE(number)) { - VALUE f10 = int_pow(10, -ndigits); - VALUE n10 = f10; - if (number < 0) { - f10 = FIXNUM_P(f10) ? fix_uminus(f10) : rb_big_uminus(f10); - } - num = rb_big_idiv(rb_dbl2big(absnum), n10); - return FIXNUM_P(num) ? fix_mul(num, f10) : rb_big_mul(num, f10); - } - number /= f; - } - else number *= f; - number = round(number); - if (ndigits < 0) number *= f; - else number /= f; + if (isinf(number) || isnan(number) || + (((long)ndigits - float_dig) * (3 + (binexp > 0)) + binexp >= 0)) { + return num; } - - if (ndigits > 0) return DBL2NUM(number); - - if (!FIXABLE(number)) { - return rb_dbl2big(number); + if ((long)ndigits * (4 - (binexp > 0)) + binexp < 0) { + return DBL2NUM(0); } - val = (long)number; - return LONG2FIX(val); + f = pow(10, ndigits); + return DBL2NUM(round(number * f) / f); } /* -- cgit v1.2.3