summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
authormarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-09-04 19:28:54 +0000
committermarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-09-04 19:28:54 +0000
commit9d2f5dff62b8bbaa9a67f38bb310ee9e3694f025 (patch)
treee7e7914dc324b016974957b6d3ed5b0cab73d5d2 /numeric.c
parent26f73a5117cd4ddba5121203f91f9d853f4dea4d (diff)
* numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33183 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/numeric.c b/numeric.c
index 201dfabd28..a767fa54c8 100644
--- a/numeric.c
+++ b/numeric.c
@@ -3320,6 +3320,7 @@ int_round(int argc, VALUE* argv, VALUE num)
{
VALUE n, f, h, r;
int ndigits;
+ long bytes;
ID op;
if (argc == 0) return num;
@@ -3331,11 +3332,15 @@ int_round(int argc, VALUE* argv, VALUE num)
if (ndigits == 0) {
return num;
}
- ndigits = -ndigits;
- if (ndigits < 0) {
- rb_raise(rb_eArgError, "ndigits out of range");
+
+ /* If 10**N / 2 > num, then return 0 */
+ /* We have log_256(10) > 0.415241 and log_256(1/2) = -0.125, so */
+ bytes = FIXNUM_P(num) ? sizeof(long) : rb_funcall(num, rb_intern("size"), 0);
+ if (-0.415241 * ndigits - 0.125 > bytes ) {
+ return INT2FIX(0);
}
- f = int_pow(10, ndigits);
+
+ f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -3344,6 +3349,10 @@ int_round(int argc, VALUE* argv, VALUE num)
if (neg) x = -x;
return LONG2NUM(x);
}
+ if (TYPE(f) == T_FLOAT) {
+ /* then int_pow overflow */
+ return INT2FIX(0);
+ }
h = rb_funcall(f, '/', 1, INT2FIX(2));
r = rb_funcall(num, '%', 1, f);
n = rb_funcall(num, '-', 1, r);