summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-11-29 17:39:36 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-11-29 17:39:36 +0000
commit68336beb509b16404bc3a7e0e85eaaad8e9b8d30 (patch)
tree9f27c490edacc685ea1bc8bdeb8bc4e51c4a8658
parentee490943c14e214cf9bee3d488d1ec6ba9b886fa (diff)
merge revision(s) 33158,33185,33186:
* numeric.c (flo_round): substitute machine dependent magic number. * numeric.c (flo_round): Make Float#round round big values [bug #5272] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@33898 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog9
-rw-r--r--numeric.c59
-rw-r--r--test/ruby/test_float.rb13
-rw-r--r--version.h2
4 files changed, 44 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index 680df9c0e3..2214472786 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Nov 30 02:37:32 2011 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * numeric.c (flo_round): Make Float#round round big values [bug
+ #5272]
+
+Wed Nov 30 02:37:32 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_round): substitute machine dependent magic number.
+
Wed Nov 30 02:28:22 2011 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
* numeric.c (int_round): Integer#round always returns an Integer [Bug
diff --git a/numeric.c b/numeric.c
index 962d3f3883..a2b91191ef 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,18 +1534,24 @@ 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);
- frexp (number , &binexp);
+ if (ndigits == 0) {
+ return dbl2ival(number);
+ }
+ frexp(number, &binexp);
/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
- Recall that up to 17 digits can be needed to represent a double,
- so if ndigits + exp >= 17, the intermediate value (number * 10 ** ndigits)
+ Recall that up to float_dig digits can be needed to represent a double,
+ so if ndigits + exp >= float_dig, the intermediate value (number * 10 ** ndigits)
will be an integer and thus the result is the original number.
If ndigits + exp <= 0, the result is 0 or "1e#{exp}", so
if ndigits + exp < 0, the result is 0.
@@ -1553,44 +1562,18 @@ flo_round(int argc, VALUE *argv, VALUE num)
10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
binexp/4 <= exp <= binexp/3
If binexp <= 0, swap the /4 and the /3
- So if ndigits + binexp/(4 or 3) >= 17, the result is number
+ 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 - 17) * (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);
}
/*
diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb
index fb37d73831..c244447bd7 100644
--- a/test/ruby/test_float.rb
+++ b/test/ruby/test_float.rb
@@ -315,7 +315,9 @@ class TestFloat < Test::Unit::TestCase
assert_raise(FloatDomainError) { inf.ceil }
assert_raise(FloatDomainError) { inf.round }
assert_raise(FloatDomainError) { inf.truncate }
+ end
+ def test_round_with_precision
assert_equal(1.100, 1.111.round(1))
assert_equal(1.110, 1.111.round(2))
assert_equal(11110.0, 11111.1.round(-1))
@@ -323,6 +325,17 @@ class TestFloat < Test::Unit::TestCase
assert_equal(10**300, 1.1e300.round(-300))
assert_equal(-10**300, -1.1e300.round(-300))
+ assert_equal(1.0e-300, 1.1e-300.round(300))
+ assert_equal(-1.0e-300, -1.1e-300.round(300))
+
+ bug5227 = '[ruby-core:39093]'
+ assert_equal(42.0, 42.0.round(308), bug5227)
+ assert_equal(1.0e307, 1.0e307.round(2), bug5227)
+
+ assert_raise(TypeError) {1.0.round("4")}
+ assert_raise(TypeError) {1.0.round(nil)}
+ def (prec = Object.new).to_int; 2; end
+ assert_equal(1.0, 0.998.round(prec))
end
VS = [
diff --git a/version.h b/version.h
index 4e5b0953bc..efb8d8e5fb 100644
--- a/version.h
+++ b/version.h
@@ -1,5 +1,5 @@
#define RUBY_VERSION "1.9.3"
-#define RUBY_PATCHLEVEL 1
+#define RUBY_PATCHLEVEL 2
#define RUBY_RELEASE_DATE "2011-11-30"
#define RUBY_RELEASE_YEAR 2011