Issue #8553 has been updated by headius (Charles Nutter).


In JRuby, Bignum#size is implemented using Java's BigInteger.bitLength().

bitLength doco:

public int bitLength()
Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit. For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. (Computes (ceil(log2(this < 0 ? -this : this+1))).

Implementation in JRuby:

    @JRubyMethod(name = "size")
    public IRubyObject size() {
        return getRuntime().newFixnum((value.bitLength() + 7) / 8);
    }

This leads to the deviation you see in RubySpec, where JRuby and Rubinius differ from MRI on various Bignum sizes.

Perhaps the least impact and most value would be to reimplement MRI's Bignum#size in terms of actual 2's complement bit length, the same way as JRuby (and apparently Rubinius)?

RE: Fixnum#size... I think Ruby should introduce a new constant for native word size, and encourage people to use it.
----------------------------------------
Feature #8553: Bignum#size (and Fixnum#size)
https://bugs.ruby-lang.org/issues/8553#change-40096

Author: akr (Akira Tanaka)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 


How about changing Bignum#size to a well defined behavior?

Recently I changed Bignum implementation to use 128 bit integer type
if the type is available.  (r41379)

After that, rubyspec fails with Bignum#size as follows:

| 1)
| Bignum#size returns the number of bytes in the machine representation in multiples of four FAILED
| Expected 16
|  to equal 12
| 
http://a.mrkn.jp/~mrkn/chkbuild/mavericks/ruby-trunk-m64-o3/log/20130620T231101Z.log.html.gz

I think this failure itself is not a problem.
This is just an over-specification of rubyspec.
Actually the test also fails before r41379 on platforms which doesn't support 64 bit integer type.

It is because the Bignum#size returns multiples of sizeof(BDIGIT), not 4.
sizeof(BDIGIT) can be 2 or 4 before r41379 or 8 since r41379.
The test only considers platforms sizeof(BDIGIT) is 4.

However this test failure reminds me that I always felt that current
Bignum#size (and Fixnum#size) behavior is not useful.

I guess almost all people doesn't interest sizeof(BDIGIT).

So I'd like to change Bignum#size to return number of bytes.
It means val.size returns n if val is a Bignum and
256**n <= abs(val) < 256**(n+1).

One exception is that val.size returns 0 if val is Bignum zero.

My considerations:

* The above Bignum#size behavior is based on absolute values, abs(n).
  This is compatible to current behavior and easy to understand.
  There are other possibilities: exception on negative values and
  definition on 2's complement value.
  I think exception is too different from current behavior.
  A definition based on 2's complement is difficult to treat sign bits.

* Bignum#size returns number of bytes, not bits.
  I think some method which returns number of bits may be useful but
  it is different from current Bignum#size.
  It is better to name another one, such as bitsize and it is not this issue.

* Fixnum#size is difficult to change.
  Currently Fixnum#size returns sizeof(long).
  Some programs, mspec for example, uses it to obtain a word size. 
  So it is difficult to change because compatibility.
  However I doubt such use is correct.
  If a program want to detect 64bit platform, Fixnum#size should not be used
  because it returns 4 on LLP64 platforms (64bit Windows).
  It is better to use [0].pack("l!").size for sizof(long) and
  [nil].pack("p").size for sizeof(char *).

  However some people may hope Fixnum and Bignum consistent.
  For that purpose, Fixnum#size should also be changed same way.
  It will breaks some applications, though.

Any opinion?



-- 
http://bugs.ruby-lang.org/