How to return a fixed length binary representation of an integer in Ruby?
Use string format.
"%08b" % 1
# => "00000001"
Converting Integers to Binary in Ruby
I am not fond of this approach since I'm sure there's an even more clever and/or compact, Ruby-esque way of accomplishing it. But using your method of loading binary digits into an array, and then joining, what you have can be done in a little more straight-forward fashion:
def to_binary(n)
return "0" if n == 0
r = []
32.times do
if (n & (1 << 31)) != 0
r << 1
else
(r << 0) if r.size > 0
end
n <<= 1
end
r.join
end
Or, using @500_error's suggestion:
def to_binary(n)
if n >= 0
n.to_s(2)
else
31.downto(0).map { |b| n[b] }.join
end
end
The asymmetry to deal with negative versus non-negative is a little annoying, though. You could do something like:
def to_binary(n)
31.downto(0).map { |b| n[b] }.join.sub(/^0*/, "")
end
Ruby Convert integer to binary to integer array of set bits
This would work:
i = 98
(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?)
#=> [2, 32, 64]
Fixnum#bit_length
returns the position of the highest "1" bitFixnum#[n]
returns the integer's nth bit, i.e.0
or1
Fixnum#<<
shifts the bit to the left.1 << n
is equivalent to 2n
Step by step:
(0...i.bit_length).map { |n| i[n] }
#=> [0, 1, 0, 0, 0, 1, 1]
(0...i.bit_length).map { |n| i[n] << n }
#=> [0, 2, 0, 0, 0, 32, 64]
(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?)
#=> [2, 32, 64]
You might want to reverse
the result.
In newer versions of Ruby (2.7+) you could also utilize filter_map
and nonzero?
to remove all 0
values:
(0...i.bit_length).filter_map { |n| (i[n] << n).nonzero? }
#=> [2, 32, 64]
Is there a way to force ruby to output results in binary
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.
Ruby binary string to hexadecimal without loosing 0000
You can use this:
binary = "0000010000000000000000000000000000000000000000000000000000000000"
[binary].pack("B*").unpack("H*").first
# => "0400000000000000"
binary.to_i(2)
will convert the value to a number. A number does not know about leading zeros. pack("B*")
will convert 8 bit each to a byte, giving you a binary encoded String. 8 x 0 is "\x00"
, a zero byte. So unlike the number, the string preserves the leading zeros. unpack("H*")
then converts 4 bits each into their hex representation. See Array#pack
and String#unpack
for more information.
Decomposing an integer into an array of integers by bit manipulation
def decompose n, l, a = []
n, r = n.divmod(2 ** l)
a.unshift(r)
n.zero? ? a : decompose(n, l, a)
end
decompose(100, 4) # => [6, 4]
decompose(123456, 6) # => [30, 9, 0]
Looping through bits in an integer, ruby
To determine the length of the longest sequence of consecutive 1's, this is more efficient:
def longest_one_chain(n)
c = 0
while n != 0
n &= n >> 1
c += 1
end
c
end
The method simply counts how many times you can "bitwise AND" the number with itself shifted 1 bit to the right until it is zero.
Example:
______ <-- longest chain
01011011100001111110011110101010 c=0
AND 0101101110000111111001111010101
1001100000111110001110000000 c=1, 1’s deleted
AND 100110000011111000111000000
100000011110000110000000 c=2, 11’s deleted
AND 10000001111000011000000
1110000010000000 c=3, 111’s deleted
AND 111000001000000
110000000000000 c=4, 1111’s deleted
AND 11000000000000
10000000000000 c=5, 11111’s deleted
AND 1000000000000
0 c=6, 111111’s deleted
What does the .size on number mean in ruby?
I always suggest to check the method you're not sure about using the following scheme:
Check where the method comes from (using Object#
method
):number.method(:size)
#=> #<Method: Fixnum#size>Open docs and learn what it does for
Fixnum#size
and how it works.2.1 If you're using IRB, you can run
help 'Fixnum#size'
to get the docs right in your console
2.2 If you're using pry, you can go withshow-doc Fixnum#size
(installpry-doc
gem first)
In Ruby 2.1.8 method was defined in Fixnum#size
.
Starting from Ruby 2.4 it's defined in
Integer#size
:
Returns the number of bytes in the machine representation of int.
Ruby to_s conversion to binary argument error
I think you are trying to convert a number in Ruby to a string with it's binary representation. This is possible with (if the number is actually a number in Ruby, e.g. Fixnum) :
4.to_s 2
# => "100"
But in your case, what you are getting after calling gets
is a string, and the to_s
method of the String class simply returns itself, and doesn't take any arguments, hence the error.
You can fix it by calling gets.to_i
instead of just gets
, so the read string of contents will be converted to an integer in Ruby (you should be sure that you will only be reading numbers at there).
And I believe you are trying to assign the binary representation (as a string) of n
into the variable n2
, for that you should be doing
n2 = n.to_s(2)
If you just do :
(n2=n).to_s
Because of the parenthesis, first n2
will be assigned the value of n
, then to_s
will be called on n2
, the string version of n2
will be returned, and nothing else happens. First thing you should be doing is the conversion, then the assignment.
And also you should pass in a string while calling String#count, i.e. you should call n2.count('2')
instead of n2.count(2)
.
Related Topics
Calling a Class Method Within a Class
Accessing Headers from Sinatra
Rvm with Jruby 1.7.0 "Unknown Ruby Interpreter"
What Do I Need to Do to Get Hash.From_Xml() to Work
"Ruby.Exe Is Not Recognized as an Internal or External Command" in Windows 7
Lion: Problem with Rvm Installing Rubies - Problem Related to Openssl
User Selected CSS Stylesheet in Rails
Ruby: Controlling Printing in Scientific Notation
Using CSS to Style Ruby Objects in Erb
Os X Mavericks Install Rvm Warning
Ruby Metaprogramming, How Does Rspec's 'Should' Work
Sinatra + Heroku + Datamapper Deploy Issues with Dm-Sqlite-Adapter
How to Create Pretty JSON in Chef (Ruby)
Ruby Syntactic Sugar: Dealing with Nils