Ruby's Bignum

Hi everyone. I’m porting some C code to pure ruby, and I would like to
keep Ruby from turning my numbers in to Bignums. Is that possible?

For example, in C:

printf(“number: %d\n”, 0xd76aa478);

Prints “number: -680876936”

In ruby:

irb(main):001:0> puts 0xd76aa478
3614090360
=> nil

Is it possible to get ruby to behave the same way as C? This seems like
something easy to do, I’m just having a hard time figuring it out.
Thank you!

–Aaron

Hi,

Is it possible to get ruby to behave the same way as C? This seems like
something easy to do, I’m just having a hard time figuring it out.
Thank you!

Try this:

irb(main):001:0> puts [0xd76aa478].pack(‘L’).unpack(‘l’).first
-680876936
=> nil

Regards,

Park H.

On 6/4/06, Aaron P. [email protected] wrote:

irb(main):001:0> puts 0xd76aa478
3614090360
=> nil

Is it possible to get ruby to behave the same way as C? This seems like
something easy to do, I’m just having a hard time figuring it out.
Thank you!

Hi Aaron,

Short answer, no. In Ruby, as you know, everything is an object and in
the C code implementing ruby, this is represented by pointers to these
objects. These pointers have a type of VALUE which is basically a
32-bit integer. But it would be pretty inefficient to store integers
as memory-allocated objects so instead it stores them in the same
32-bit integer. (This is true for FixInt, BigNum is an object ref). So
how does the interpreter know the difference between an object
reference and a FixInt? It relies on the fact that all memory pointers
are are on 4 or 8-byte boundaries so that leaves at least the last 2
bits free. These last two bits are used to specify whether VALUE is an
integer, a refence or possibly a symbol, true or false value or nil.
This means that there are only 30 bits left to specify the value of
FixInt. So the maximum value you can store in a FixInt is 0x3FFFFFFF
and the minimum is -0x40000000.

irb(main):007:0> 0x40000000.class
=> Bignum
irb(main):008:0> 0x3fffffff.class
=> Fixnum
irb(main):009:0> -0x40000000.class
=> Fixnum
irb(main):010:0> -0x40000001.class
=> Bignum

Hope that makes sense.

Cheers,
Dave

On 6/4/06, David B. [email protected] wrote:

In ruby:

integer, a refence or possibly a symbol, true or false value or nil.
irb(main):010:0> -0x40000001.class
=> Bignum

Hope that makes sense.

Cheers,
Dave

Sorry, this answer should have been under “and I would like to keep
Ruby from turning my numbers in to Bignums. Is that possible?”

To cast an Integer to a 32-bit signed integer you can use pack/unpack
like Park said, or you could do it like this;

def to_32_bit_signed(val)
val |= -0x100000000 if (val & 0x80000000) > 0
val
end

2006/6/4, David B. [email protected]:

On 6/4/06, David B. [email protected] wrote:
To cast an Integer to a 32-bit signed integer you can use pack/unpack
like Park said, or you could do it like this;

def to_32_bit_signed(val)
val |= -0x100000000 if (val & 0x80000000) > 0
val
end

And if you need this in multiple places of the program then it’s
probably worth while to create a new subclass of Integer that
restricts itself to 32 bit calculations

Int32 < Integer
def initialize(x)
@val = to_32(x)
end
def to_int …
def coerce(a,b) …
def hash() …
def eql?(x)
def ==(x) …
def +(x) …
def -(x) …
private
def to_32(x) …

end

It’s a nice excercise to get used to operators and numercial coercion.
:slight_smile:

Maybe we can even generalize that and put it into the standard lib -
something like a restricted integer that calculates with a max number
of bits.

Kind regards

robert

“Robert K.” [email protected] writes:

And if you need this in multiple places of the program then it’s
def eql?(x)
Maybe we can even generalize that and put it into the standard lib -
something like a restricted integer that calculates with a max number
of bits.

This is indeed a good Ruby exercise, but if it ever ends up in the
standard library, I would then vote for it to be re-implemented in C, as
the Ruby version would be hugely less efficient than the native
32-bit-integer operations that are already available in C.

2006/6/4, Lloyd Z. [email protected]:

And if you need this in multiple places of the program then it’s
probably worth while to create a new subclass of Integer that
restricts itself to 32 bit calculations

It’s a nice excercise to get used to operators and numercial coercion. :slight_smile:

Maybe we can even generalize that and put it into the standard lib -
something like a restricted integer that calculates with a max number
of bits.

This is indeed a good Ruby exercise, but if it ever ends up in the
standard library, I would then vote for it to be re-implemented in C, as
the Ruby version would be hugely less efficient than the native
32-bit-integer operations that are already available in C.

Completely agree!

robert

On Sun, Jun 04, 2006 at 04:23:38PM +0900, Park H. wrote:

Try this:

irb(main):001:0> puts [0xd76aa478].pack(‘L’).unpack(‘l’).first
-680876936
=> nil

Thanks Park! Thats exactly what I was looking for.

–Aaron

On Sun, Jun 04, 2006 at 06:32:54PM +0900, Robert K. wrote:
[snip]

It’s a nice excercise to get used to operators and numercial coercion. :slight_smile:

Maybe we can even generalize that and put it into the standard lib -
something like a restricted integer that calculates with a max number
of bits.

I was hoping this would be in the standard lib since I have to do it a
lot! I will be filling out that class so that I won’t have to type as
much though. :slight_smile:

–Aaron

Aaron P. wrote:

Hi everyone. I’m porting some C code to pure ruby, and I would like to
keep Ruby from turning my numbers in to Bignums. Is that possible?

For example, in C:

printf(“number: %d\n”, 0xd76aa478);

Prints “number: -680876936”

It’s just another variation on pack/unpack, but with bit-struct (from
RAA):

require ‘bit-struct’

class C < BitStruct
signed :foo, 32
end

c = C.new
c.foo = 0xd76aa478

printf(“number: %d\n”, c.foo)

==> number: -680876936