Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compute one's complement using Ruby's bitwise operators?

What I want:

assert_equal 6, ones_complement(9)   # 1001 => 0110
assert_equal 0, ones_complement(15)  # 1111 => 0000
assert_equal 2, ones_complement(1)   # 01 => 10

the size of the input isn't fixed as in 4 bits or 8 bits. rather its a binary stream.

What I see:

v = "1001".to_i(2)                 => 9

There's a bit flipping operator ~

(~v).to_s(2)                       => "-1010"
sprintf("%b", ~v)                  => "..10110"
~v                                 => -10

I think its got something to do with one bit being used to store the sign or something... can someone explain this output ? How do I get a one's complement without resorting to string manipulations like cutting the last n chars from the sprintf output to get "0110" or replacing 0 with 1 and vice versa

like image 853
Gishu Avatar asked Dec 06 '22 05:12

Gishu


1 Answers

Ruby just stores a (signed) number. The internal representation of this number is not relevant: it might be a FixNum, BigNum or something else. Therefore, the number of bits in a number is also undefined: it is just a number after all. This is contrary to for example C, where an int will probably be 32 bits (fixed).

So what does the ~ operator do then? Wel, just something like:

class Numeric
    def ~
        return -self - 1
    end
end

...since that's what '~' represents when looking at 2's complement numbers.

So what is missing from your input statement is the number of bits you want to switch: a 32-bits ~ is different from a generic ~ like it is in Ruby.

Now if you just want to bit-flip n-bits you can do something like:

class Numeric
    def ones_complement(bits)
        self ^ ((1 << bits) - 1)
    end
end

...but you do have to specify the number of bits to flip. And this won't affect the sign flag, since that one is outside your reach with XOR :)

like image 178
Rutger Nijlunsing Avatar answered Mar 02 '23 21:03

Rutger Nijlunsing