Publi

Bailando con bits III. Mostrando el valor binario de un número [bash, C, C++, PHP, Java, Python, Ruby]

photo-1425036458755-dc303a604201_red

De todos es sabido que un ordenador, internamente trabaja con ceros y unos, simplemente eso, a partir de ese simple valor, verdadero o falso, abierto o cerrado, existe o no existe es capaz de formar sonidos, imágenes, textos y cualquier cosa que podamos imaginarnos.

Aunque no vamos a hacer algo tan complicado, muchas veces puede que tengamos un valor entre manos y queramos saber qué bits hay a uno y qué bits hay a cero aunque sólo sea para verificar que una operación se está realizando como debe o porque estamos aprendiendo a utilizar este sistema de numeración y queremos verificar que todo nos sale bien.

En este post, voy a poner algunos métodos que podemos utilizar en varios lenguajes de programación, o en consola, con este propósito.

Decimal a binario en consola

Empecemos en consola. Vamos a utilizar dos formas, una utilizando perl (en realidad nos valdría cualquier lenguaje en el que podamos hacer un script, como awk; aunque en perl lo he visto muy sencillo):

1
2
$ echo 'printf("%b", 12)' | perl
1100

Pocas implementaciones de printf incluyen %b para mostrar un número en base2, pero en perl podemos usar números de hasta 18446744073709551615 (64 bits), sin problema. Podríamos recoger el número en una variable así:

1
2
$ numero=15; echo 'printf("%b", '$numero')' | perl
1111

Parece que hacemos algo raro con las comillas, y es que $numero será una variable de nuestro interprete de consola (en mi caso Bash) y no de perl. Otra opción que tenemos es:

1
2
$ numero=128; echo "printf('%b', $numero)" | perl
10000000

Podemos hacerlo como queramos.

Otra opción es utilizar el programa bc, en el que no tendremos en principio restricción del número de bits, todo puede ser que tu ordenador se tire media hora calculando bits, pero él puede con lo que le eches:

1
2
$ echo "obase=2; 1234" | bc
10011010010

O si lo preferimos con una variable:

1
2
$ numero=170; echo "obase=2;$numero" | bc
10101010

Lo importante aquí es obase en el que decimos la base que queremos como salida de las operaciones de bc. En realidad con bc podemos hacer muchas más cosas (sumas, restas, multiplicaciones, divisiones, raíces, senos, cosenos, logaritmos, incluso sencillos programas de lógica.

C

Vale, mi lenguaje favorito, lo dejo para el segundo. Es verdad que en algunas implementaciones de la biblioteca estándar de C, la función printf incluye un indicador de formato %b (para binario, como el ejemplo de perl de antes), pero no es lo normal. Así que si queremos sacar el valor en binario de un número, tendremos que hacerlo a mano, para ello, tengo aquí una función a mano (podemos meterla en un archivo sacabits.h e incluirlo en nuestro proyecto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#ifndef _SACABITS_H
#define _SACABITS_H 1

#define typetobin(type) const char* type##_a_binario(type num)  \
  {                             \
  return printBits(sizeof(type), &num);             \
  }


const char* getBits(size_t const size, void* ptr)
{
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i, j;
    char *resultado = (char*)malloc(100);
    char *res = resultado;

    for (i=size-1;i>=0;i--)
    {
        for (j=7;j>=0;j--)
        {
            byte = b[i] & (1<<j);
            byte >>= j;
        *res='0'+byte;
        res++;
        }
    *res++=' ';
    }

    *res='\0';
    return res-size*9;
}

typetobin(float);
typetobin(double);
typetobin(char);
typetobin(int);

#endif /* _SACABITS_H */

Ahora, hacemos un programa de ejemplo:

1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>
#include <stdio.h>
#include "sacabits.h"

int main(int argc, char *argv[])
{
  printf ("Un entero: (%d) = %s\n", 1234, int_a_binario(1234));
  printf ("Un double: (%lf) = %s\n", 1234.32, double_a_binario(1234.32));
  printf ("Un char: (%d) = %s\n", 198, char_a_binario(198));
}

O incluso podemos sacar en binario cosas más complejas, como un struct completo (eso sí, si el struct es muy grande, la salida será enorme:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdlib.h>
#include <stdio.h>
#include "sacabits.h"

struct miStruct
{
  char texto[4];
  int numero;
};

int main(int argc, char *argv[])
{
  struct miStruct test = { "HOLA", 2047 };

  printf ("Un struct: %s\n", getBits(sizeof(test), &test));
}

Con esto podemos aprender cosas muy curiosas sobre la memoria de un ordenador, o de cómo organiza C las cosas.

C++

Vamos avanzando, y es que en C++ tenemos métodos mucho más sencillos de sacar un valor en bits de una variable. Utilizando bitset, incluido en std. De la siguiente forma:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <bitset>

int main()
{
  std::cout << "123 = " << std::bitset<8>(123)  << std::endl;
  std::cout << "1234 = " << std::bitset<16>(1234)  << std::endl;
  std::cout << "123456789 = " << std::bitset<32>(123456789)  << std::endl;
  std::cout << "12345678901234567 = " << std::bitset<64>(12345678901234567)  << std::endl;
}

Java

Venga, también lo haremos en Java en este post. En este caso, de forma sencilla, cogemos un entero y lo pasamos a binario:

1
2
3
4
5
6
7
8
public class Sacabits
{
  public static void main(String args[])
    {
    int i = 615243;
    System.out.println("Valor: " + Integer.toBinaryString(i));
    }
}

Integer.toBinaryString(numero) nos devolverá una cadena de caracteres con cada uno de los bits del número en cuestión.

PHP

Como sabéis que me gusta PHP, también quiero dejar un pequeño código en este lenguaje, aunque es lo más simple del mundo, ya que tenemos una función que nos saca directamente el valor en base2 de un número decimal:

1
2
3
<?php
echo "123: ".decbin(123)."\n";
echo "1928: ".decbin(1928)."\n";

Python

Python, como siempre, tiene cosas muy masticadas, y desde aquí podemos ver un ejemplo desde la línea de comandos de python:

1
2
3
4
>>> bin(123)
'0b1111011'
>>> "{0:b}".format(123)
'1111011'

Con el primer método, mucho más rápido veremos el valor en binario, pero con la base delante (0b), de la misma forma que podemos expresar un número en diferentes bases. Con la segunta forma, veremos directamente el valor en base 2, depende de nuestras necesidades escoger uno u otro.

Ruby

Ruby no es mi punto fuerte, pero también quería poner un ejemplo en este lenguaje. Podemos hacerlo de varias formas, entre otras, estas dos me parecen muy interesantes:

1
print "%b" % 123

y

1
print 9.to_s(2)

Ahora os toca a vosotros, ¿algún otro lenguaje con el que podamos completar este post?

Foto: ahmadreza sajadi (unsplash)

También podría interesarte....

Leave a Reply