Быстрый способ преобразования двоичного числа в десятичное число

Мне нужно как можно быстрее преобразовать двоичное число, например, unsigned int bin_number = 10101010 в его десятичное представление (т.е. 170)? Каков наилучший алгоритм?

Ответ 1

Используя шаблоны, вы можете решить эту проблему во время компиляции.

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; };

Двоичный шаблон создается снова с меньшим num, пока num не достигнет нуля, и специализация будет использоваться в качестве условия завершения.

Пример: std::cout << binary<10101010>::value;

Для проблемы времени выполнения:

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;
}

Ответ 2

Ну, если это "число" на самом деле является строкой, полученной из некоторого источника (считанного из файла или из пользователя), который вы преобразовали в число (считая его более подходящим для фактического числа), что вполне Вероятно, вы можете использовать std::bitset для преобразования:

#include <bitset>

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

(Конечно, 32 здесь определяется реализацией и может быть более правильно написан как std::numeric_limits<unsigned int>::digits.)

Но если это действительно число (целочисленная переменная) в (очень) первом месте, которое вы могли бы сделать:

#include <string>

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

(используя С++ 11 to_string). Но это, вероятно, не будет наиболее эффективным способом, поскольку другие представили более эффективные алгоритмы, основанные на числах. Но, как сказано, я сомневаюсь, что вы действительно получите это число как фактическую целочисленную переменную в самом первом месте, а скорее прочитайте ее из какого-либо текстового файла или из пользователя.

Ответ 3

На самом деле, если вы пишете unsigned int bin_number = 10101010, это интерпретируется компилятором как десятичное число.

Если вы хотите написать двоичный литерал в своем исходном коде, вы должны использовать BOOST_BINARY. Затем вам просто нужно распечатать его с помощью cout, по умолчанию используется десятичная дробь...

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

Ответ 4

Поскольку С++ 11 (даже если С++ 11 в этом отношении более ограничен, чем С++ 14), функция может быть constexpr поэтому избегайте необходимости в template иметь значение времени компиляции.

Здесь версия С++ 14 совместима:

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

    while (num)
    {
        res = 10 * res + num % 10;
        num /= 10;
    }
    return res;
}

А для литералов вы можете даже использовать двоичные литералы начиная с С++ 14:

0b1010'1010 // or 0b10101010 without separator

Ответ 5

Если вам известно количество двоичных цифр, с которыми вы имеете дело, и оно всегда исправлено, и двоичное число приходит в строке (как если бы оно было бы прочитано из файла или stdin) во время выполнения (т.е. невозможно преобразовать время компиляции), тогда вы можете применить этот подход:

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 );
}

Это предполагает фиксированное восьмизначное двоичное число. называется так:

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

Если у вас было шестнадцатибитное число, вы все равно можете его использовать:

const char* bin_number = "1010101010101010";

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

Обратите внимание, что здесь явно нет ограничений, и я полагаюсь на то, что LSB "1" всегда 1, а "0" всегда 0 (поэтому не проверяем, что он фактически является двоичным вводом.)

Естественно, он довольно конкретный и не очень гибкий, но он выполняет эту работу, и я не уверен, что вы получите гораздо быстрее.

Ответ 6

Во время компиляции вам даже не нужен шаблон. Вы можете просто использовать нотацию 0b.

#include <iostream>
int main(){
    int i = 0b10101010;
    std::cout << i << std::endl;
    return 0;
}