zimkies - 2 months ago 7

Ruby Question

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

`-1[-1]`

Answer

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.

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

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.