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.

`[]`
operator:
``` 1[0] -> 1 2[1] -> 1 ```

I tried
`-1[-1]`
(to access the last one), but that doesn't work.

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

https://ruby-doc.org/core-2.2.0/Fixnum.html#method-i-5B-5D

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.

# Solution

``````> 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.