From: David Balmain Date: 2006-06-04T16:38:27+09:00 Subject: Re: Ruby's Bignum On 6/4/06, David Balmain wrote: > On 6/4/06, Aaron Patterson 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" > > > > 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! > > 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 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