summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
authormarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-09-04 20:14:29 +0000
committermarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-09-04 20:14:29 +0000
commit75c42535c9e49a3afae910d533874933558857ed (patch)
treef0c9f23a1966dc378c8e8c7fcfa6aa4d96019ebe /numeric.c
parent269de36cd06e58726d33bc85429419ede7c3c9d6 (diff)
* 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
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c50
1 files changed, 16 insertions, 34 deletions
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);
}
/*