randy newfield - 1 year ago 52

Ruby Question

I want to do a demo for some peers, and I want to force IRB to return values in only binary.

For example it currently returns the result in base 10 no matter which base the input is in:

`0b1111`

# => 15 #should return 1111 or 0b1111

0b0001 | 0b0011

# => 3 #should return 0011 or 0b0011

Is there a way to force this result? I want to demo bitwise operators and it is much easier for them to understand if they see the bits flowing around rather than base 10 numbers being returned, that I would have to convert to base 2 afterwards.

Also I would like for all results to be in multiples of 4 bits. If possible with underscores or spaces separating the half byte groupings.

For example:

`0b0001_0101`

# => 0b0001_0101 #or 0b0001 0101, or 0001 0101, or 0001_0101

If I result does not need to be represented by 4 bits (example 3, 11) pad it to 4, 8, 16 bits in length depending on the number.

Answer Source

If you write `0b0001.class`

you will find that it is Fixnum.

Writing `puts 0b1000`

shows `8`

, and it's clear this Fixnum is stored in base 10.

So as far as I'm aware, there isn't any way to prevent the conversion to base 10.

If you want to control the way that Fixnum objects are displayed in IRB, you can implement a custom `inspect`

method for the class:

```
class Fixnum
def inspect
unpadded_binary_string = to_s(2)
binary_width = if unpadded_binary_string.length % 4 == 0
unpadded_binary_string.length
else
((unpadded_binary_string.length / 4) * 4) + 4
end
padded_binary_string = "%0#{binary_width}d" % unpadded_binary_string
# join groups of 4 with an underscore
padded_binary_string = padded_binary_string.scan(/.{4}/).join("_")
"0b" + padded_binary_string
end
end
```

results:

```
irb(main):007:0> 0b1000
=> 0b1000
irb(main):011:0> 99999999
=> 0b0101_1111_0101_1110_0000_1111_1111
```

The inspect method uses `to_s(2)`

, which takes an integer and produces a string representation of it's binary. But the zeroes at the front of the binary are lost when it's converted to base 10. That's why the inspect method
needs to manually add zeroes to the front of the string.

There's no way I can think of to add the correct number of zeroes to the front of the string in a completely dynamic way.

What I'm doing here is calculating the minimum width (in a multiple of 4) that can contain the unpadded binary string. So if the unpadded length is 5 characters, the final width will be 8. If the unpadded length is 2, the final length is 4.

Instead of calculating it on-the-go, you could alternatively set the `binary_width`

as an external variable that you change at runtime, then reference it from the inspect function.