¿Cómo convertir una cadena o un entero a binario en Ruby?

168

¿Cómo se crean enteros 0..9 y operadores matemáticos + - * / en cadenas binarias? Por ejemplo:

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

¿Hay alguna manera de hacer esto con Ruby 1.8.6 sin usar una biblioteca?

Mcmaloney
fuente
Cuando dice que desea convertir operadores matemáticos en cadenas binarias, ¿qué quiere decir exactamente? ¿Usar la representación ASCII escrita en binario?
bta
¿Supongo que querías hacer el popular algoritmo genético? :-)
nemesisfixx

Respuestas:

372

Tienes Integer#to_s(base)y String#to_i(base)disponible para ti.

Integer#to_s(base) convierte un número decimal en una cadena que representa el número en la base especificada:

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

mientras que el reverso se obtiene con String#to_i(base):

"1001".to_i(2) #=> 9
Mike Woodhouse
fuente
24
@TomRavenscroft Además, puede usar ("%08b" % int)o ("%08b" % string)para devolver un número fijo de bits.
decaimiento
1
¡Mike brillante, rubí brillante!
Tamer Shlash
44
-9.to_s(2) => "-1001"¿Alguien puede explicar esto?
user1201917
1
Para aquellos confundidos por el código de @ decay como yo, él está usando 'sprintf': apidock.com/ruby/Kernel/sprintf
Taylor Liss
@ user1201917 ¿Qué hay de malo en eso? 9Está 1001en binario.
preferred_anon
41

Hice una pregunta similar . Según la respuesta de @sawa , la forma más sucinta de representar un número entero en una cadena en formato binario es usar el formateador de cadena:

"%b" % 245
=> "11110101"

También puede elegir qué tan larga será la representación de cadena, lo que podría ser útil si desea comparar números binarios de ancho fijo:

1.upto(10).each { |n| puts "%04b" % n }
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
Alejandro
fuente
66
Hice una prueba local para convertir enteros a cadenas binarias, pero el resultado muestra que códigos como 245.to_s(2)serán más rápidos que"%b" % 245
Green Su
Además, esto no funciona correctamente con valores negativos.
alex
21

Al retomar la idea de la tabla de búsqueda de bta, puede crear la tabla de búsqueda con un bloque. Los valores se generan cuando se accede por primera vez y se almacenan para más adelante:

>> 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
fuente
11

Naturalmente Integer#to_s(2), lo usaría , String#to_i(2)o "%b"en un programa real, pero, si está interesado en cómo funciona la traducción, este método calcula la representación binaria de un entero dado utilizando operadores básicos:

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

Para comprobar que funciona:

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
fuente
4

Si solo está trabajando con los dígitos individuales 0-9, es probable que sea más rápido crear una tabla de búsqueda para que no tenga que llamar a las funciones de conversión cada vez.

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"

La indexación en esta tabla hash usando el número entero o la representación de cadena de un número producirá su representación binaria como una cadena.

Si necesita que las cadenas binarias tengan un cierto número de dígitos (mantenga los ceros a la izquierda), cambie x.to_s(2) a sprintf "%04b", x(donde 4es el número mínimo de dígitos a usar).

bta
fuente
@ bta: estoy codificando todos estos caracteres en binario para poder usarlos en un algoritmo genético. Realmente me gusta la idea de una tabla de búsqueda para la codificación / decodificación ya que el conjunto está limitado a 0..9 y + - * /
mcmaloney
2

Si está buscando una clase / método Ruby, lo usé y también he incluido las pruebas:

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
fuente