Project

General

Profile

Backport #5271

Integer#round should never return a Float

Added by marcandre (Marc-Andre Lafortune) over 8 years ago. Updated about 8 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
[ruby-core:39261]

Description

Integer#round sometimes returns... a float!

42.round(-1e9) # => 0.0

There's a check for out of range arguments, but it's not really needed and is machine dependent.

The following patch fixes the issue by optimizing for most cases and double checking for the rare extremely unlikely case where 10**ndigits does not fit in a bignum but num does and has almost ndigits digits.

Committed to trunk but would be nice to backport for Ruby 1.9.3.

diff --git a/numeric.c b/numeric.c
index 201dfab..a767fa5 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);

Associated revisions

Revision 9d2f5dff
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • 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

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision 33183
Added by marcandre (Marc-Andre Lafortune) over 8 years ago

  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Revision ee490943
Added by naruse (Yui NARUSE) about 8 years ago

merge revision(s) 33183,33185:

    * numeric.c (int_round): Integer#round always returns an Integer [Bug
      #5271]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@33897 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 33897
Added by naruse (Yui NARUSE) about 8 years ago

merge revision(s) 33183,33185:

* numeric.c (int_round): Integer#round always returns an Integer [Bug
  #5271]

History

#1

Updated by marcandre (Marc-Andre Lafortune) over 8 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r33183.
Marc-Andre, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • numeric.c (int_round): Integer#round always returns an Integer [Bug #5271]

Updated by marcandre (Marc-Andre Lafortune) over 8 years ago

  • Status changed from Closed to Open

Opening backport request.

#3

Updated by naruse (Yui NARUSE) about 8 years ago

  • Target version deleted (1.9.3)
#4

Updated by naruse (Yui NARUSE) about 8 years ago

  • Status changed from Open to Closed

This issue was solved with changeset r33897.
Marc-Andre, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


merge revision(s) 33183,33185:

* numeric.c (int_round): Integer#round always returns an Integer [Bug
  #5271]

Also available in: Atom PDF