Двоичный файл, два последовательных бита 1

#c

#c

Вопрос:

Я пытаюсь реализовать с помощью C, который выводит количество двух последовательных 1-бит в целое число без перекрытия. Это мой код:

 #include <stdio.h>

int numPairs(int num) {
    int count = 0;
    while (num) {
        num = (num amp; (num << 1));
        count  ;
    }
    return count / 2;
}

int main(){
    printf("%dt", numPairs(10000));
    printf("%dt", numPairs(146));
    printf("%dt", numPairs(7645));
    printf("%dt", numPairs(16383));
    return 0;
}
  

Мой вывод 1 0 1 7

Но вывод должен быть 1 0 3 7

Все правильно, за исключением 7645 , и я не знаю, что с этим не так.

Для 7645 моего кода выдает результат 1 , но правильный результат 3 .

Комментарии:

1. «Но на выходе должно быть 1 0 3 7» . Почему? Значение count находится 3 в конце цикла, перед return его половиной, которая является 1 .

2. @CinCout, потому что 7645 равно 0x1ddd

Ответ №1:

Ваш метод не подходит:

Вы подсчитываете количество итераций, необходимых для обнуления выражения n = n amp; (n << 1); . Это будет максимальное количество последовательных бит 1. Если пары битов разделены, результат будет отличаться от количества неперекрывающихся пар битов.

В случае в 7645 , 0x1ddd или 0001 1101 1101 1101 в десятичной системе счисления имеется 3 группы по 3 последовательных бита 1, но они обнуляются при параллельных 3 итерациях цикла, следовательно, count / 2 является 1 .

Вы должны использовать другой алгоритм, такой как:

 int numPairs(int num) {
    int count = 0;
    unsigned int x = num;
    while (x) {
        if ((x amp; 3) == 3) {
            count  ;
            x >>= 2;
        } else {
            x >>= 1;
        }
    }
    return count;
}
  

Комментарии:

1. 1 за объяснение алгоритма, используемого OP. Я рассматривал решение, похожее на ваше, но не был уверен, что стандарт C гарантирует неизменность битового шаблона при переходе от подписанного к неподписанному. Для реализаций дополнения 2s, я думаю, битовый шаблон остается неизменным, но переносим ли он вообще?

2. @4386427: для архитектур с дополнением non two нельзя делать предположения о положении знакового бита и потенциальном присутствии битов заполнения, поэтому проблема не полностью указана для целых чисел со знаком. Помимо обсуждения языковых вопросов, которые мне нравятся, эти соображения не имеют практического применения, но для ясности OP следует сделать num unsigned.

Ответ №2:

В случае, если важна скорость, это также может быть сделано с помощью операций с битовыми манипуляциями:

 int numPairs(uint32_t x) {
    return __builtin_popcount((((x ^ 0x55555555)   0x55555555) ^ 0x55555555) amp; x);
}
  

Это приводит к получению 1 бита в верхнем бите каждой непересекающейся 2-разрядной группы единиц, а затем подсчитывает 1 бит.