Hi,

here is my solution and some unit tests.

(I didn't know that it's possible to write a block with an array  
argument,
as in "define_method meth do |*other|". That's a nice feature.)

Regards,
Boris


### c_int.rb

class UnsignedFixedWidthInt

   def initialize(value, bits)
     raise ArgumentError.new('number of bits must be > 0') if bits <= 0
     @bits  = bits
     @value = value % 2**@bits
   end

   # operators returning a new FixedWidthInt
   %w{& ^ | << >> + - * / +@ -@ ~@}.each do |operator|
     define_method operator do |*other|
       self.class.new(@value.send(operator, *other), @bits)
     end
   end

   # methods forwarded to @value
   %w{== < > <=> inspect to_s to_i to_int}.each do |meth|
     define_method meth do |*other|
       @value.send(meth, *other)
     end
   end

   def coerce(other)
     Integer == other ? [other, @value] : [Float(other), Float(@value)]
   end
end

class SignedFixedWidthInt < UnsignedFixedWidthInt
   def initialize(value, bits)
     super(value, bits)
     # value is negative if MSB is set:
     @value -= 2**@bits if @value[@bits - 1] == 1
   end
end




### c_int_test.rb

require 'c_int'
require 'test/unit'

class CIntTest < Test::Unit::TestCase
   def test_no_bits
     assert_raises(ArgumentError) { UnsignedFixedWidthInt.new(0, 0) }
     assert_raises(ArgumentError) { UnsignedFixedWidthInt.new(0, -1) }
   end

   def test_one_bit
     n = UnsignedFixedWidthInt.new(0xFF, 1)
     assert_equal 1, n

     n += 1
     assert_equal 0, n

     n = SignedFixedWidthInt.new(0xFF, 1)
     assert_equal(-1, n)

     n += 1
     assert_equal 0, n

     n += 1
     assert_equal(-1, n)
   end

   def test_unsigned
     n = UnsignedFixedWidthInt.new(0xFF, 8)
     assert_equal 255, n

     n += 2
     assert_equal 1, n

     n = n << 1
     assert_equal 2, n

     n = n >> 1
     assert_equal 1, n

     assert_equal 254, (~n)

     n += 12
     assert_equal 13, n

     n = n & 0x0E
     assert_equal 12, n

     n = n * 24
     assert_equal 32, n

     n = n / 15
     assert_equal 2, n
   end

   def test_signed
     n = SignedFixedWidthInt.new(0x01, 8)
     assert_equal  1, n

     n = n << 7
     assert_equal(-128, n)

     n -= 1
     assert_equal 127, n

     n = n >> 6
     assert_equal 1, n

     n -= 2
     assert_equal(-1, n)

     n = n ^ 0xF3
     assert_equal  12, n

     n = n | 0x01
     assert_equal  13, n

     n = +n
     assert_equal 13, n

     n = -n
     assert_equal(-13, n)
   end

   def test_too_wide
     n = UnsignedFixedWidthInt.new(0x0, 8)
     n += 0xFFEE
     assert_equal 238, n
   end

   def test_signed_shift_right
     n = SignedFixedWidthInt.new(0x80, 8)
     n = n >> 1
     assert_equal(-64, n) # with sign extension
   end

   def test_equal
     s1 = SignedFixedWidthInt.new(-1, 4)
     s2 = SignedFixedWidthInt.new(-1, 4)
     s3 = SignedFixedWidthInt.new(1, 4)
     u1 = UnsignedFixedWidthInt.new(1, 4)
     u2 = UnsignedFixedWidthInt.new(1, 4)
     assert u1 != s1
     assert s1 != s3
     assert u1 == u2
     assert s1 == s2
     assert s3 == u1
     assert(-1 == s1)
     assert s1 == -1
   end

   def test_conversions
     n = SignedFixedWidthInt.new(-100, 7)
     assert "-100", n.to_s
     assert "-100", n.inspect
     assert(-100, n.to_i)
     assert(-100, n.to_int)
   end

   def test_coerce
     n = UnsignedFixedWidthInt.new(1, 4)
     assert 1.1 > n
     assert 0.9 < n
     assert 1 == n
   end

   def test_comparison
     s = SignedFixedWidthInt.new(-1, 4)
     u = UnsignedFixedWidthInt.new(1, 4)
     assert u > s
     assert s < u
     assert s < 0
     assert u > 0
     assert 0 > s
     assert 0 < u
     assert_equal(-1, s <=> u)
     assert_equal 1, u <=> s
     assert_equal 0, 1 <=> u
     assert_equal 0, -1 <=> s
   end
end