Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 [] operator: 1[0] -> 1 2[1] -> 1

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

like image 838
zimkies Avatar asked Sep 28 '16 17:09

zimkies


1 Answers

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.

Solution 1

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 to get the sign bit, do not remove 1 from the bit_length

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

Solution 2

You could also just use a < 0 comparison:

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

Solution 3

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]

Bonus

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.

like image 130
sokkyoku Avatar answered Nov 10 '22 13:11

sokkyoku