194

How do you create integers 0..9 and math operators + - * / in to binary strings. For example:

 0 = 0000,
 1 = 0001, 
 ...
 9 = 1001

Is there a way to do this with Ruby 1.8.6 without using a library?

Morgan
  • 19,934
  • 8
  • 58
  • 84
mcmaloney
  • 2,374
  • 3
  • 19
  • 19
  • When you say you want to convert math operators to binary strings, what exactly do you mean? Use the ASCII representation written in binary? – bta Feb 26 '10 at 22:46
  • I guess u wanted to do the popular Genetic Algorithm thing? :-) – JWL Mar 13 '12 at 19:10

8 Answers8

429

You have Integer#to_s(base) and String#to_i(base) available to you.

Integer#to_s(base) converts a decimal number to a string representing the number in the base specified:

9.to_s(2) #=> "1001"

while the reverse is obtained with String#to_i(base):

"1001".to_i(2) #=> 9
marzapower
  • 5,531
  • 7
  • 38
  • 76
Mike Woodhouse
  • 51,832
  • 12
  • 88
  • 127
  • 28
    @TomRavenscroft In addition, you can use `("%08b" % int)` or `("%08b" % string)` to return a fixed number of bits. – jrdi Aug 27 '13 at 15:29
  • 1
    Brilliant Mike, Brilliant Ruby! – Tamer Shlash May 15 '14 at 20:13
  • 5
    `-9.to_s(2)` `=> "-1001"` Can someone explain this? – user1201917 Mar 15 '17 at 14:52
  • 1
    For those confused by @decay's code like myself, he is using 'sprintf': https://apidock.com/ruby/Kernel/sprintf – Taylor Liss Sep 04 '18 at 00:15
  • @user1201917 What's wrong with that? `9` is `1001` in binary. – preferred_anon Oct 23 '19 at 13:01
  • @preferred_anon Unbelievable, but just 2 hours ago I discussed binary conversions in ruby with my colleague Last time IRL I discussed binary numbers in ruby about 5 years ago. And now I check notifications on stackoverflow and see your answer to 3-years-ago comment... about binary numbers in ruby. What a coincidence! Yes, `9` is `1001` but `(-9)` is not `-1001`. `to_i` depends on `NUM2INT` impl. which [was caused an error on negative values](https://bugs.ruby-lang.org/issues/9089) [More info](https://silverhammermba.github.io/emberb/c/#methods) – user1201917 Oct 23 '19 at 16:40
  • @user1201917 How remarkable! I must say I very rarely come across negative binary numbers, but at least when I've seen them in maths the notation `-1001` would be correct for `-9`. Is there some notation for a signed bit or something that is more common among programmers? – preferred_anon Oct 23 '19 at 17:43
  • @preferred_anon negative numbers usually represented as two's complements. For -9 it will be `(inverse of ...00001001) + 1 -> ...11110111`. It can be "verified" with `-9[i]` method which returns the bit at a `i` position – user1201917 Oct 24 '19 at 08:12
47

I asked a similar question. Based on @sawa's answer, the most succinct way to represent an integer in a string in binary format is to use the string formatter:

"%b" % 245
=> "11110101"

You can also choose how long the string representation to be, which might be useful if you want to compare fixed-width binary numbers:

1.upto(10).each { |n| puts "%04b" % n }
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
Community
  • 1
  • 1
Alexander Popov
  • 23,073
  • 19
  • 91
  • 130
  • 8
    I did some local test to convert integers to binary string, but the result shows that codes like `245.to_s(2)` will be faster than `"%b" % 245` – Green Su May 13 '14 at 08:58
  • 1
    Also this doesn't work properly with negative values. – alex Aug 13 '19 at 20:43
23

Picking up on bta's lookup table idea, you can create the lookup table with a block. Values get generated when they are first accessed and stored for later:

>> lookup_table = Hash.new { |h, i| h[i] = i.to_s(2) }
=> {}
>> lookup_table[1]
=> "1"
>> lookup_table[2]
=> "10"
>> lookup_table[20]
=> "10100"
>> lookup_table[200]
=> "11001000"
>> lookup_table
=> {1=>"1", 200=>"11001000", 2=>"10", 20=>"10100"}
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
11

You would naturally use Integer#to_s(2), String#to_i(2) or "%b" in a real program, but, if you're interested in how the translation works, this method calculates the binary representation of a given integer using basic operators:

def int_to_binary(x)
  p = 0
  two_p = 0
  output = ""

  while two_p * 2 <= x do
    two_p = 2 ** p
    output << ((two_p & x == two_p) ? "1" : "0")
    p += 1
  end

  #Reverse output to match the endianness of %b
  output.reverse
end

To check it works:

1.upto(1000) do |n|
  built_in, custom = ("%b" % n), int_to_binary(n)
  if built_in != custom
    puts "I expected #{built_in} but got #{custom}!"
    exit 1
  end
  puts custom
end
joews
  • 29,767
  • 10
  • 79
  • 91
4

If you're only working with the single digits 0-9, it's likely faster to build a lookup table so you don't have to call the conversion functions every time.

lookup_table = Hash.new
(0..9).each {|x|
    lookup_table[x] = x.to_s(2)
    lookup_table[x.to_s] = x.to_s(2)
}
lookup_table[5]
=> "101"
lookup_table["8"]
=> "1000"

Indexing into this hash table using either the integer or string representation of a number will yield its binary representation as a string.

If you require the binary strings to be a certain number of digits long (keep leading zeroes), then change x.to_s(2) to sprintf "%04b", x (where 4 is the minimum number of digits to use).

bta
  • 43,959
  • 6
  • 69
  • 99
  • @bta- I'm encoding all these characters into binary so I can use them in a genetic algorithm. I really like the idea of a lookup table for the encode/decode since the set is limited to 0..9 and +-*/ – mcmaloney Feb 27 '10 at 06:30
3

In ruby Integer class, to_s is defined to receive non required argument radix called base, pass 2 if you want to receive binary representation of a string.

Here is a link for an official documentation of String#to_s

  1.upto(10).each { |n|  puts n.to_s(2) }
zhisme
  • 2,368
  • 2
  • 19
  • 28
Jay
  • 31
  • 1
  • 1
    This answer would improve significantly if you could edit it and describe how the code solves the problem – Cleptus Oct 30 '20 at 11:22
2

If you are looking for a Ruby class/method I used this, and I have also included the tests:

class Binary
  def self.binary_to_decimal(binary)
    binary_array = binary.to_s.chars.map(&:to_i)
    total = 0

    binary_array.each_with_index do |n, i|
      total += 2 ** (binary_array.length-i-1) * n
    end
    total
   end
end

class BinaryTest < Test::Unit::TestCase
  def test_1
   test1 = Binary.binary_to_decimal(0001)
   assert_equal 1, test1
  end

 def test_8
    test8 = Binary.binary_to_decimal(1000)
    assert_equal 8, test8
 end

 def test_15
    test15 = Binary.binary_to_decimal(1111)
    assert_equal 15, test15
 end

 def test_12341
    test12341 = Binary.binary_to_decimal(11000000110101)
    assert_equal 12341, test12341
 end
end
Puce
  • 1,003
  • 14
  • 28
SharifH
  • 29
  • 3
-1

I am almost a decade late but if someone still come here and want to find the code without using inbuilt function like to_S then I might be helpful.

find the binary

def find_binary(number)
  binary = []  
  until(number == 0)
    binary << number%2
    number = number/2
  end
  puts binary.reverse.join
end