Какой самый быстрый алгоритм возвращает степень числа, которое является степенью 2? - PullRequest
6 голосов
/ 17 апреля 2011

Учитывая n = 2 ^ k, как я могу найти k, предполагая, что n - 32-разрядное целое число, используя побитовый C / C ++?

Ответы [ 7 ]

6 голосов
/ 17 апреля 2011

GCC имеет __builtin_clz, который преобразуется в BSR на x86 / x64, CLZ на ARM и т. Д. И эмулирует инструкцию, если оборудование не реализует ее.
Visual C ++ 2005 и выше имеет_BitScanReverse.

Используя эти функции, вы можете получить свой k

5 голосов
/ 17 апреля 2011

Википедия пишет, как это сделать, используя побитовые операторы:

/**
 * Returns the floor form of binary logarithm for a 32 bit integer.
 * −1 is returned if ''n'' is 0.
 */
int floorLog2(unsigned int n) {
  if (n == 0)
    return -1;

  int pos = 0;
  if (n >= 1<<16) { n >>= 16; pos += 16; }
  if (n >= 1<< 8) { n >>=  8; pos +=  8; }
  if (n >= 1<< 4) { n >>=  4; pos +=  4; }
  if (n >= 1<< 2) { n >>=  2; pos +=  2; }
  if (n >= 1<< 1) {           pos +=  1; }
  return pos;
}

Код взят из: Википедия о: двоичный логарифм с тех пор эта страница была изменена в исходной версии с примером кодаее еще можно найти: Википедия по: двоичному логарифму (24 мая 2011 г.)

3 голосов
/ 17 апреля 2011

Ну, вы могли бы использовать тот факт, что двоичный показатель явно хранится в числах с плавающей запятой:

unsigned log2(unsigned x)
{
    float f = x;
    memcpy(&x, &f, sizeof x);
    return (x >> 23) - 127;
}

Я не знаю, насколько это быстро, и, конечно, это не самое портативное решение, но я нахожу это довольно интересным.

И просто для забавы, вот совершенно другое, относительно простое решение:

unsigned log2(unsigned x)
{
    unsigned exp = 0;
    for (; ;)
    {
        switch (x)
        {
            case 128: ++exp;
            case 64: ++exp;
            case 32: ++exp;
            case 16: ++exp;
            case 8: ++exp;
            case 4: ++exp;
            case 2: ++exp;
            case 1: return exp;
            case 0: throw "illegal input detected";
        }
        x >>= 8;
        exp += 8;
    }
}

А вот совершенно развернутое решение:

#define CASE(exp) case (1 << (exp)) : return (exp);

unsigned log2(unsigned x)
{
    switch (x)
    {
        CASE(31) CASE(30) CASE(29) CASE(28)
        CASE(27) CASE(26) CASE(25) CASE(24)
        CASE(23) CASE(22) CASE(21) CASE(20)
        CASE(19) CASE(18) CASE(17) CASE(16)
        CASE(15) CASE(14) CASE(13) CASE(12)
        CASE(11) CASE(10) CASE( 9) CASE( 8)
        CASE( 7) CASE( 6) CASE( 5) CASE( 4)
        CASE( 3) CASE( 2) CASE( 1) CASE( 0)
        default: throw "illegal input";
    }
}
2 голосов
/ 17 апреля 2011

продолжайте смещать вправо значение n до тех пор, пока не получите 1.count количество требуемых сдвигов вправо.

1 голос
/ 17 апреля 2011

Для переносимого решения (не прибегая к специфическим для реализации вещам), вы можете использовать бинарное измельчение, которое, вероятно, является одним из наиболее эффективных способов, не связанных с непереносимыми вещами.Например, скажем, ваше целое число составляет 8 бит:

// Given n = 2^k, k >= 0, returns k.

unsigned int getK (unsigned int n) {
    if (n <= 8) {
        if (n <= 2) {
            if (n == 1) return 0;
            return 1;
        }
        if (n == 4) return 2;
        return 3;
    }
    if (n <= 32) {
        if (n == 16) return 4;
        return 5;
    }
    if (n == 64) return 6;
    return 7;
}

Это становится немного громоздким, так как размер целого увеличивается, но вы должны записать его только один раз: -)

0 голосов
/ 04 октября 2013

Если вы используете GCC, я думаю, что это самый быстрый способ:

int ilog2(int value) {
 return 31 - __builtin_clz(value);
}

Где __builtin_clz - оптимизированная встроенная функция GCC.

0 голосов
/ 20 апреля 2011

Дано: 0 <= n <= 2**32, что означает 0 <= k <= 32, и k может быть представлен байтом.2 ** 32 байта ОЗУ в целом не являются чрезмерными, поэтому самым быстрым методом вычисления может быть простой поиск в таблице.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...