Найти бит высшего порядка в C - PullRequest
41 голосов
/ 10 сентября 2008

то, что мне нужно, это то, что я могу ввести число, и оно вернет бит самого высокого порядка. Я уверен, что есть простой способ. Ниже приведен пример вывода (слева - ввод)

1 -> 1
2 -> 2
3 -> 2
4 -> 4
5 -> 4
6 -> 4
7 -> 4
8 -> 8
9 -> 8
...
63 -> 32

Ответы [ 13 ]

81 голосов
/ 10 сентября 2008

От восторга хакера:

int hibit(unsigned int n) {
    n |= (n >>  1);
    n |= (n >>  2);
    n |= (n >>  4);
    n |= (n >>  8);
    n |= (n >> 16);
    return n - (n >> 1);
}

Эта версия для 32-битных целых, но логика может быть расширена для 64-битных или более.

36 голосов
/ 30 декабря 2012

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

1<<(fls(input)-1)
29 голосов
/ 10 сентября 2008

Это должно сработать.

int hob (int num)
{
    if (!num)
        return 0;

    int ret = 1;

    while (num >>= 1)
        ret <<= 1;

    return ret;
}

варочная поверхность (1234) возвращает 1024
варочная панель (1024) возвращает 1024
варочная поверхность (1023) возвращает 512

27 голосов
/ 10 сентября 2008

как запутанный код? Попробуйте это:

1 << (int) log2 (x) </p>

6 голосов
/ 21 сентября 2009

Это можно легко решить с помощью существующих библиотечных вызовов.

int highestBit(int v){
  return fls(v) << 1;
}

Справочная страница Linux содержит более подробную информацию об этой функции и ее аналогах для других типов ввода.

4 голосов
/ 10 сентября 2008

Быстрый способ сделать это через справочную таблицу. Для 32-разрядного ввода и 8-разрядной справочной таблицы требуется только 4 итерации:

int highest_order_bit(int x)
{
    static const int msb_lut[256] =
        {
            0, 0, 1, 1, 2, 2, 2, 2, // 0000_0000 - 0000_0111
            3, 3, 3, 3, 3, 3, 3, 3, // 0000_1000 - 0000_1111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_0000 - 0001_0111
            4, 4, 4, 4, 4, 4, 4, 4, // 0001_1000 - 0001_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_0000 - 0010_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0010_1000 - 0010_1111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_0000 - 0011_0111
            5, 5, 5, 5, 5, 5, 5, 5, // 0011_1000 - 0011_1111

            6, 6, 6, 6, 6, 6, 6, 6, // 0100_0000 - 0100_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0100_1000 - 0100_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_0000 - 0101_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0101_1000 - 0101_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_0000 - 0110_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0110_1000 - 0110_1111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_0000 - 0111_0111
            6, 6, 6, 6, 6, 6, 6, 6, // 0111_1000 - 0111_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1000_0000 - 1000_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1000_1000 - 1000_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_0000 - 1001_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1001_1000 - 1001_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_0000 - 1010_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1010_1000 - 1010_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_0000 - 1011_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1011_1000 - 1011_1111

            7, 7, 7, 7, 7, 7, 7, 7, // 1100_0000 - 1100_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1100_1000 - 1100_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_0000 - 1101_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1101_1000 - 1101_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_0000 - 1110_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1110_1000 - 1110_1111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_0000 - 1111_0111
            7, 7, 7, 7, 7, 7, 7, 7, // 1111_1000 - 1111_1111
        };

    int byte;
    int byte_cnt;

    for (byte_cnt = 3; byte_cnt >= 0; byte_cnt--)
    {
        byte = (x >> (byte_cnt * 8)) & 0xff;
        if (byte != 0)
        {
            return msb_lut[byte] + (byte_cnt * 8);
        }
    }

    return -1;
}
4 голосов
/ 10 сентября 2008

Ядро linux имеет ряд таких полезных битопов, которые наиболее эффективно закодированы для ряда архитектур. Вы можете найти универсальные версии в include / asm-generic / bitops / fls.h (и друзья), но см. Также include / asm-x86 / bitops.h для определения, используя встроенная сборка, если скорость важна, а портативность - нет.

4 голосов
/ 10 сентября 2008

Постоянно удаляется младший бит, приходит на ум ...

int highest_order_bit( int x )
{
    int y = x;
    do { 
        x = y;
        y = x & (x-1); //remove low order bit
    }
    while( y != 0 );
    return x;
}
2 голосов
/ 03 февраля 2017

Немного опоздал на эту вечеринку, но самое простое решение, которое я нашел, учитывая современный GCC в качестве компилятора, это просто:

static inline int_t get_msb32 (register unsigned int val)
{
  return 32 - __builtin_clz(val);
}

static inline int get_msb64 (register unsigned long long val)
{
  return 64 - __builtin_clzll(val);
}

Он даже относительно переносим (по крайней мере, он будет работать на любой платформе GCC).

2 голосов
/ 03 июня 2015

Если вам не нужно переносимое решение и ваш код выполняется на x86-совместимом процессоре, вы можете использовать встроенную функцию _BitScanReverse (), предоставляемую компилятором Microsoft Visual C / C ++. Он сопоставляется с инструкцией CPU BSR, которая возвращает установленный старший бит.

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