Unsigned equivalent of a negative FixNum

143 Views Asked by At

How do I determine the unsigned interpretation of a negative FixNum?

# unexpected, true
(~0b01111011).to_s(2) == ("-" + (~0b01111011).abs.to_s(2))

# expected, false
~0b01111011 == 0b10000100

How would I write a function such that:

123.unsigned_not(8) == 132

Or alternatively:

-124.unsigned(8) == 132

Edit: I could do this via strings, but the solution is far from satisfying

class Fixnum
  def unsigned_not(bits=16)
    to_s(2).rjust(bits,'0').gsub(/[01]/, '0' => '1', '1' => '0').to_i(2)
  end
end
2

There are 2 best solutions below

0
joanbm On BEST ANSWER

Fixnum#~ operator does Two's complement and Ruby uses internally arbitrary big numbers & arithmetic, so if you want to do an inversion on a fixed base, you need to work in required bounds and interpret results accordingly:

class Fixnum
  def neg(base=8)
    # xor with max in specific base
    self ^ (2**base - 1)
  end
end

132.neg             # 123
123.neg             # 132
~-124.neg           # 132
132.to_s(2)         # 1000010
132.neg.to_s(2)     # 0111101
# different result for a different base, as expected
132.neg(16).to_s(2) # 111111110111101
1
LeChatDeNansen On

May be you could try this test :

(0x800000FF & ~0b01111011) == (0x800000FF & 0b10000100)

assuming 0x... standing for Hex constant and & standing for the AND operator for the language you are dealing with. leading 0x8 would force 32 bits extension ?