zimkies zimkies - 1 year ago 49
Ruby Question

How can I access a ruby integer's sign bit?

I would like to access a ruby integer's sign bit directly.

Ruby allows access to an int's bits through the


1[0] -> 1
2[1] -> 1

I tried
(to access the last one), but that doesn't work.

Answer Source

You can understand this by looking at the documentation for Fixnum#[] :

Returns the +n+th bit in the binary representation of fix, where fix[0] is the least significant bit


A Fixnum is not an array, thus its #[] function can (and does) behave differently to what you'd expect from an array.

To access the most significant bit you can use #bit_length - 1

> a = 5
=> 5
> a[a.bit_length - 1]
=> 1

However, this excludes the sign bit for negative numbers, so

> 5.bit_length
=> 3
> -5.bit_length
=> 3

From examining the documentation, I could not find a better way of deducing the sign bit than a simple < 0 check.


> a = -5
=> -5
> sign_bit = a < 0 ? 1 : 0
=> 1

Why #size won't necessary work

First of all, let's read the documentation for #size:

Returns the number of bytes in the machine representation of fix.

From the implementation of the function we can gather that if the stored number is inside the bounds of a 32-bit signed integer if will be stored in one. In this case #size returns 4. If it is larger it will be stored in a 64-bit integer and #size will return 8.

However not all of these bits are in use. If you store the number 5 (0b101) your 32 bits will be occupied as such

10100000 00000000 00000000 00000000

Negative numbers are most of the time stored as the 2s complement (not sure if applicable for ruby) which would mean that if you store the number -5 your 32 bits will be occupied as such

11011111 11111111 11111111 11111111

Thus you can also access the sign bit with the following code:

x[x.size * 8 - 1]

If you're curious about why 5[-1] does not throw an exception and still returns a number, you can look at the source code for Fixnum#[] (on the documentation page previously mentioned).

if (i < 0) return INT2FIX(0);

It is made to just return 0 if your index is a negative number.