miércoles, 29 de junio de 2011

Números binarios en C++

ATENCIÓN ACTUALIZACIÓN (2014-12-13): El estándar de C++ de 2014 incluye la posibilidad de usar literales binarios directamente con la notación 0b1001.


En C++ (y en C y en otros muchos lenguajes de programación) hay tres formas de escribir números enteros literales.
  1. En base 10 (decimal) cuando escribo algo como 1042348
  2. En base 16 (hexadecimal) cuando prefijo 0x como en 0x3FFF
  3. En base 8 (octal) cuando prefijo sólo 0 como en 0663
Cuando se programa en bajo nivel muchas veces es más directo escribir directamente en base 2 (binario), ¿pero cómo? Me he topado con la siguiente macro que lo consigue

#define Ob(x)  ((unsigned)Ob_(0 ## x ## uL))
#define Ob_(x) (x & 1 | x >> 2 & 2 | x >> 4 & 4 | x >> 6 & 8 |  \
 x >> 8 & 16 | x >> 10 & 32 | x >> 12 & 64 | x >> 14 & 128)

El truco se basa en dos pasos, el primero Ob (no es un cero, es una o) pone delante un 0 (que sí es un cero) y detrás un "uL". El "uL" es la forma que tenemos de decirle al C++ que el número es sin signo y largo. El cero, por otra parte, sí que es importante ya que nos va a convertir el número a octal. Lo que tenemos entonces es un número binario interpretado como un número octal. ¿Cómo afecta eso a su valor?

Un número binario se expresa de la siguiente forma [$$ n=\cdots + d_3 2^3 + d_2 2^2 + d_1 2^1 + d_0 2^0 $$] donde los [$d_i$] son los dígitos. Los dígitos serán o cero o uno. Al escribir el número binario como octal lo que hacemos es  [$$ n=\cdots + d_3 8^3 + d_2 8^2 + d_1 8^1 + d_0 8^0 $$] pero aún con los dígitos en binario. Así que lo único que necesitamos es leer los bits de tres en tres ya que [$8=2^3$].  Justamente eso es lo que hace Ob_.

Por ejemplo:
Ob(1001) //Como binario es 9 en decimal
Ob_(01001uL) //Como octal es 513 en decimal y 1_000_000_001 en binario
9 //Tomando un bit de cada 3 en el 513 

0 comentarios:

Publicar un comentario en la entrada