Алгоритм поиска наиболее значимого бита

Привет и спасибо, что нашли время ответить на мой вопрос.

Мой друг был задан на собеседовании следующий вопрос: "Учитывая двоичное число, найдите самый значительный бит". Я сразу подумал о следующем решении, но не уверен, что это правильно.

А именно, разделите строку на две части и преобразуйте обе части в десятичные. Если левый субаррейм равен 0 в десятичном значении, то выполняется двоичный поиск в правом подмассиве, ища 1.

Это мой другой вопрос. Является ли самый старший бит, самый левый в двоичном числе? Можете ли вы показать мне пример, когда 0 является самым значимым битом с примером и объяснением.

EDIT:

В ответах ниже, кажется, немного замешаны, поэтому я уточняю вопрос, чтобы уточнить его. Интервьюер сказал: "У вас есть веб-сайт, на котором вы получаете данные до тех пор, пока самый старший бит не укажет, чтобы прекратить передачу данных." Как бы вы сказали, чтобы программа остановила передачу данных "

Ответ 1

Вы также можете использовать смещение битов. Псевдо-код:

number = gets
bitpos = 0
while number != 0
  bitpos++             # increment the bit position
  number = number >> 1 # shift the whole thing to the right once
end
puts bitpos

если число равно нулю, битпоп равен нулю.

Ответ 2

Поиск наиболее значимого бита в слове (т.е. вычисление log2 с округлением) с использованием только C-подобных инструкций языка может быть сделано с использованием довольно известного метода, основанного на последовательностях De Bruijn. Например, для 32-битного значения

unsigned ulog2(uint32_t v)
{ /* Evaluates [log2 v] */
  static const unsigned MUL_DE_BRUIJN_BIT[] = 
  {
     0,  9,  1, 10, 13, 21,  2, 29, 11, 14, 16, 18, 22, 25,  3, 30,
     8, 12, 20, 28, 15, 17, 24,  7, 19, 27, 23,  6, 26,  5,  4, 31
  };

  v |= v >> 1;
  v |= v >> 2;
  v |= v >> 4;
  v |= v >> 8;
  v |= v >> 16;

  return MUL_DE_BRUIJN_BIT[(v * 0x07C4ACDDu) >> 27];
}

Однако на практике более простые методы (например, развернутый двоичный поиск) обычно работают так же хорошо или лучше.

Ответ 3

Это один из подходов (не обязательно самый эффективный, хотя, особенно если ваша платформа имеет однокоординатное решение для поиска-первого-одного или count-leading-zeros или что-то подобное), предполагая, что два знака дополняют целые числа со знаком и 32-разрядная целая ширина.

int mask = (int)(1U<<31); // signed integer with only bit 32 set
while (! n & mask)        // n is the int we're testing against
  mask >>= 1;             // take advantage of sign fill on right shift of negative number
mask = mask ^ (mask << 1) // isolate first bit that matched with n

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

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

Ответ 4

Редактированный вопрос действительно совсем другой, хотя и не очень ясный. Кто ты"? Веб-сайт или программист программы, который считывает данные с веб-сайта? Если вы являетесь веб-сайтом, вы заставляете программу останавливаться, отправляя значение (но что, байт, возможно?) С его самым значительным битом. Просто ИЛИ или ДОБАВЬТЕ, что бит дюйма. Если вы программист, вы тестируете самый значительный бит полученных вами значений и прекратите чтение, когда он будет установлен. Для неподписанных байтов вы можете выполнить тест, например

bool stop = received_byte >= 128;
or
bool stop = received_byte & 128;

Для подписанных байтов вы можете использовать

bool stop = received_byte < 0;
or
bool stop = received_byte & 128;

Если вы не читаете байты, но, скажем, 32-битные слова, 128 изменяется на (1 << 31).

Ответ 5

I tihnk это своего рода трюк. Самый важный бит всегда будет 1:-). Если интервьюеры любят латеральное мышление, этот ответ должен быть победителем!

Ответ 6

Если вас интересует решение на C/С++, вы можете взглянуть на книгу "Matters Computational" Jörg Arndt, где вы имеют эти функции, определенные в разделе "1.6.1. Изоляция самого высокого и поиск его индекса":

static inline ulong highest_one_idx(ulong x)
// Return index of highest bit set.
// Return 0 if no bit is set.
{
#if defined  BITS_USE_ASM
    return  asm_bsr(x);
#else  // BITS_USE_ASM

#if  BITS_PER_LONG == 64
#define MU0 0x5555555555555555UL  // MU0 == ((-1UL)/3UL) == ...01010101_2
#define MU1 0x3333333333333333UL  // MU1 == ((-1UL)/5UL)   == ...00110011_2
#define MU2 0x0f0f0f0f0f0f0f0fUL  // MU2 == ((-1UL)/17UL)  == ...00001111_2
#define MU3 0x00ff00ff00ff00ffUL  // MU3 == ((-1UL)/257UL)  == (8 ones)
#define MU4 0x0000ffff0000ffffUL  // MU4 == ((-1UL)/65537UL) == (16 ones)
#define MU5 0x00000000ffffffffUL  // MU5 == ((-1UL)/4294967297UL) == (32 ones)
#else
#define MU0 0x55555555UL  // MU0 == ((-1UL)/3UL) == ...01010101_2
#define MU1 0x33333333UL  // MU1 == ((-1UL)/5UL)   == ...00110011_2
#define MU2 0x0f0f0f0fUL  // MU2 == ((-1UL)/17UL)  == ...00001111_2
#define MU3 0x00ff00ffUL  // MU3 == ((-1UL)/257UL)  == (8 ones)
#define MU4 0x0000ffffUL  // MU4 == ((-1UL)/65537UL) == (16 ones)
#endif

    ulong r = (ulong)ld_neq(x, x & MU0)
        + ((ulong)ld_neq(x, x & MU1) << 1)
        + ((ulong)ld_neq(x, x & MU2) << 2)
        + ((ulong)ld_neq(x, x & MU3) << 3)
        + ((ulong)ld_neq(x, x & MU4) << 4);
#if  BITS_PER_LONG > 32
    r += ((ulong)ld_neq(x, x & MU5) << 5);
#endif
    return r;

#undef MU0
#undef MU1
#undef MU2
#undef MU3
#undef MU4
#undef MU5
#endif
}

где asm_bsr реализуется в зависимости от архитектуры процессора

// i386
static inline ulong asm_bsr(ulong x)
// Bit Scan Reverse: return index of highest one.
{
    asm ("bsrl %0, %0" : "=r" (x) : "0" (x));
    return x;
}

или

// AMD64
static inline ulong asm_bsr(ulong x)
// Bit Scan Reverse
{
    asm ("bsrq %0, %0" : "=r" (x) : "0" (x));
    return x;
}

Перейдите сюда для кода: http://jjj.de/bitwizardry/bitwizardrypage.html

Ответ 7

Я не знаю, это слишком сложно:)

Я бы преобразовал двоичный номер в dec, а затем я бы сразу вернул базу 2 логарифма числа (преобразованный из float в int).

Решение - это бит (возвращаемый номер + 1), начинающийся справа.

К вашему ответу, насколько я знаю его самый левый 1