Jak przekonwertować ciąg lub liczbę całkowitą na binarną w Rubim?

168

Jak tworzyć liczby całkowite 0..9 i operatory matematyczne + - * / in do ciągów binarnych. Na przykład:

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

Czy jest sposób na zrobienie tego w Rubim 1.8.6 bez użycia biblioteki?

mcmaloney
źródło
Kiedy mówisz, że chcesz zamienić operatory matematyczne na ciągi binarne, co dokładnie masz na myśli? Użyj reprezentacji ASCII zapisanej binarnie?
bta
Chyba chciałeś zrobić popularny algorytm genetyczny? :-)
nemesisfixx

Odpowiedzi:

372

Masz Integer#to_s(base)i String#to_i(base)jesteś dostępny.

Integer#to_s(base) konwertuje liczbę dziesiętną na łańcuch reprezentujący liczbę o określonej podstawie:

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

podczas gdy odwrotność uzyskuje się z String#to_i(base):

"1001".to_i(2) #=> 9
Mike Woodhouse
źródło
24
@TomRavenscroft Ponadto możesz użyć ("%08b" % int)lub, ("%08b" % string)aby zwrócić stałą liczbę bitów.
rozpad
1
Genialny Mike, genialny Ruby!
Tamer Shlash
4
-9.to_s(2) => "-1001"Czy ktoś może to wyjaśnić?
user1201917
1
Dla tych, którzy są zdezorientowani kodem @ decay, takim jak ja, używa ``
Taylor Liss
@ user1201917 Co w tym złego? 9jest 1001binarny.
preferred_anon
41

Zadałem podobne pytanie . Opierając się na odpowiedzi @sawa , najbardziej zwięzłym sposobem przedstawienia liczby całkowitej w ciągu w formacie binarnym jest użycie programu formatującego ciąg:

"%b" % 245
=> "11110101"

Możesz także wybrać, jak długa ma być reprezentacja ciągu, co może być przydatne, jeśli chcesz porównać liczby binarne o stałej szerokości:

1.upto(10).each { |n| puts "%04b" % n }
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
Alexander
źródło
6
Zrobiłem lokalny test, aby przekonwertować liczby całkowite na ciąg binarny, ale wynik pokazuje, że kody takie jak 245.to_s(2)będą szybsze niż"%b" % 245
Zielony Nie
Również to nie działa poprawnie z wartościami ujemnymi.
Alex
21

Biorąc pod uwagę pomysł na tabelę przeglądową bta, możesz utworzyć tabelę przeglądową z blokiem. Wartości są generowane, gdy są po raz pierwszy otwierane i przechowywane na później:

>> 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
źródło
11

Można by oczywiście użyć Integer#to_s(2), String#to_i(2)albo "%b"w prawdziwym programem, ale jeśli jesteś zainteresowany w jaki prac tłumaczeniowych, metoda ta oblicza binarną reprezentację dana liczba całkowita przy użyciu podstawowych operatorów:

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

Aby sprawdzić, czy działa:

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
źródło
4

Jeśli pracujesz tylko z pojedynczymi cyframi 0-9, prawdopodobnie szybciej utworzysz tabelę odnośników, więc nie musisz za każdym razem wywoływać funkcji konwersji.

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"

Indeksowanie do tej tablicy skrótów przy użyciu reprezentacji liczby całkowitej lub łańcucha daje jej binarną reprezentację jako ciąg.

Jeśli chcesz, aby ciągi binarne miały określoną liczbę cyfr (zachowaj zera wiodące), zmień x.to_s(2)na sprintf "%04b", x(gdzie 4jest minimalna liczba cyfr do użycia).

bta
źródło
@ bta- Koduję wszystkie te znaki w postaci binarnej, aby móc ich użyć w algorytmie genetycznym. Bardzo podoba mi się pomysł tabeli przeglądowej dla kodowania / dekodowania, ponieważ zestaw jest ograniczony do 0..9 i + - * /
mcmaloney
2

Jeśli szukasz klasy / metody Ruby, użyłem tego, a także dołączyłem testy:

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
SharifH
źródło