2012-06-08 28 views
9

Tengo que convertir un número binario como por ejemplo unsigned int bin_number = 10101010 en su representación decimal (es decir, 170) lo más rápido posible? ¿Cuál es el mejor algoritmo?Forma rápida de convertir un número binario a un número decimal

+1

¿El '10101010' proviene del usuario de su programa, o es simplemente un código literal? –

+0

¿Puede dar una mejor idea de dónde se origina el número binario? ¿Se conoce en tiempo de compilación o solo en tiempo de ejecución? ¿Está almacenado en una cuerda o en alguna otra estructura? Sabiendo esto hará que responder la pregunta sea mucho más fácil. –

+0

Sí, lo siento. Normalmente obtengo el número de tiempo de ejecución, pero a veces en tiempo de compilación. Todavía estoy aprendiendo. – Nick

Respuesta

10

Usando plantillas, puede resolver este problema en tiempo de compilación.

template<unsigned long num> 
struct binary 
{ 
    static unsigned const value = 
     binary<num/10>::value << 1 | num % 10; 
}; 

// Specialization for zero 
template<> 
struct binary<0> 
{ static unsigned const value = 0; }; 

La plantilla binario se crea una instancia de nuevo con una más pequeña num, hasta num llega a cero y la especialización se utiliza como una condición de terminación.

Ejemplo: std::cout << binary<10101010>::value;

Para tiempo de ejecución problema:

unsigned binary_to_decimal(unsigned num) 
{ 
    unsigned res = 0; 

    for(int i = 0; num > 0; ++i) 
    { 
     if((num % 10) == 1) 
      res += (1 << i); 

     num /= 10; 
    } 

    return res; 
} 
+0

¿Puedes hacerme un ejemplo? – Nick

+4

Usando plantillas puedes calcular cualquier cosa en tiempo de compilación, ya que están completas. ¿Sin embargo ayuda eso al OP a hacer algo? – PlasmaHH

+1

-1: lo dudo. Si OP tuviera un ICE, que necesitaría para usar la metaprogramación, podría hacer 'const double d = 170.0;' Como está seguro que obtiene el número de entrada en tiempo de ejecución, entonces la metaprogramación está desactivada. –

3

En realidad, si usted escribe unsigned int bin_number = 10101010, esto se interpreta como un número decimal por el compilador.

Si desea escribir un Litteral binario en el código fuente, se debe utilizar BOOST_BINARY.Then sólo tiene que imprimir usando cout, decimal es el valor por defecto ...

unsigned int i = BOOST_BINARY(10101010); 
std::cout << i; // This prints 170 
+0

¿Qué es BOOST_BINARY? – Nick

+0

Algunos compiladores también son compatibles con el prefijo "0b" ('i = 0b10101010'), pero con el impulso asegura la portabilidad. – Aurel

+0

Boost es una biblioteca C++, eche un vistazo a http://www.boost.org/. – Aurel

7

Bueno, si esto "número" es en realidad una cadena obtenida de alguna fuente (leída de un archivo o de un usuario) que usted convirtió en un número (creyendo que es más apropiado para un número real), lo cual es bastante probable, puede usar un std::bitset para hacer la conversión:

#include <bitset> 

unsigned int number = std::bitset<32>("10101010").to_ulong(); 

(Por supuesto, la 32 aquí se define la aplicación y pueden escribirse más apropiadamente como std::numeric_limits<unsigned int>::digits.)

Pero si es realmente un número (variable entera) en el (muy) el primer lugar que podría hacer:

#include <string> 

unsigned int number = std::bitset<32>(std::to_string(bin_number)).to_ulong(); 

(usando C++ 11 to_string) Pero esta probablemente ya no sea la forma más eficiente, ya que otros han presentado algoritmos más eficientes basados ​​en números. Pero como dije, dudo que realmente consigas este número como una variable entera real desde el primer lugar, sino que lo lees desde algún archivo de texto o desde el usuario.

+0

Gracias, esta es una buena respuesta, pero el número no es una cadena, no puedo usar C++ 11 y pedí una solución rápida. – Nick

+0

@Nick Así que puedo preguntar de dónde lo sacaste, obviamente tienes que obtenerlo de alguna parte y dudo que realmente leas un número binario, que representa un número que solo contiene 0 y 1, eso sería una basura.Realmente tiene sentido obtener ese número de algún medio textual en primer lugar. La única excepción es cuando necesitas constantes binarias, pero para esto puedes usar otro método (el programa de plantillas de gliderkite es muy bueno). Pero para la mayoría de los casos, cuando se trata de una cadena, la solución de conjunto de bits no debe ser la más lenta (y tampoco necesita C++ 11). –

+0

por cierto tienes mi +1 – Nick

0

Si conoce el número de dígitos binarios que usted está tratando con y que siempre ha fijado y el número binario viene en una cadena (como lo sería si se lee desde un archivo o entrada estándar) en tiempo de ejecución (es decir, la conversión de tiempo de compilación no es posible) entonces usted podría adoptar este enfoque:

int to_binary(const char* c) 
{ 
    return ((c[0] & 1) ? 0x80 : 0x00) | 
      ((c[1] & 1) ? 0x40 : 0x00) | 
      ((c[2] & 1) ? 0x20 : 0x00) | 
      ((c[3] & 1) ? 0x10 : 0x00) | 
      ((c[4] & 1) ? 0x08 : 0x00) | 
      ((c[5] & 1) ? 0x04 : 0x00) | 
      ((c[6] & 1) ? 0x02 : 0x00) | 
      ((c[7] & 1) ? 0x01 : 0x00); 
} 

Esto supone un número binario fijo de ocho dígitos.llamada así:

std::cout << to_binary("10101010") << std::endl; 

Si tuviera un número de dieciséis bits todavía se podía usarlo:

const char* bin_number = "1010101010101010"; 

// Deal with 16 bits 
std::cout << (to_binary(bin_number) << 8 | to_binary(bin_number + 8)) << std::endl; 

Tenga en cuenta que claramente no hay comprobación de los límites aquí y estoy confiando en el hecho de que la LSB de '1' siempre es 1 y '0' es siempre 0 (por lo que no valida que en realidad sea una entrada binaria).

Naturalmente, es bastante específico y no muy flexible, pero cumple su función y yo soy no estoy seguro de que obtendrías mucho más rápido.

Cuestiones relacionadas