Как эта битовая операция проверяет степень 2? - PullRequest
37 голосов
/ 28 июня 2009

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

Вот условие, которое проверяет, является ли число степенью 2, используя следующее:

if((num != 1) && (num & (num - 1))) { /* make num pow of 2 */ }

Мой вопрос: как использование побитового И между числом и числом -1 определяет, является ли число степенью 2?

Ответы [ 6 ]

90 голосов
/ 28 июня 2009

Любая степень 2 минус 1 - это все единицы: ( 2 N - 1 = 111 .... b )

2 = 2^1.  2-1 = 1 (1b)
4 = 2^2.  4-1 = 3 (11b)
8 = 2^3.  8-1 = 7 (111b)

Взять, к примеру, 8. 1000 & 0111 = 0000

Так что выражение проверяет, является ли число НЕ степенью 2.

14 голосов
/ 28 июня 2009

Ну, первый случай проверит на 2 0 == 1.

Для других случаев в игру вступает num & (num - 1):

То есть, если вы берете любое число и маскируете биты из одного нижнего, вы получите один из двух случаев:

  1. если число уже является степенью двойки, то на один меньше получится двоичное число, в котором установлены только младшие биты. Использование & ничего не даст.

    • Пример с 8: 0100 & (0100 - 1) -> (0100 & 0011) -> 0000
  2. если число уже не является степенью двойки, то один меньше не будет касаться старшего бита, поэтому результат будет по крайней мере наибольшая степень двух меньше, чем число.

    • Пример с 3: 0011 & (0011 - 1) -> (0011 & 0010) -> 0010

    • Пример с 13: 1101 & (1101 - 1) -> (1101 & 1100) -> 1100

Таким образом, фактическое выражение находит все, что не является степенью двойки, включая 2 0 .

6 голосов
/ 28 июня 2009

Ну

если у вас X = 1000, то x-1 = 0111. И 1000 && 0111 равно 0000.

Каждое число X, которое является степенью 2, имеет x-1, который имеет единицы в позиции x, имеет нули. И побитовые и 0 и 1 всегда равны 0.

Если число х не является степенью двойки, например, 0110. Х-1 - это 0101, а и дает 0100.

Для всех комбинаций в пределах 0000 - 1111 это приводит к

   X  X-1 X && X-1  
0000 1111 0000   
0001 0000 0000 
0010 0001 0000
0011 0010 0010
0100 0011 0000
0101 0100 0100
0110 0101 0100
0111 0110 0110
1000 0111 0000
1001 1000 1000
1010 1001 1000
1011 1010 1010
1100 1011 1000
1101 1100 1100
1110 1101 1100
1111 1110 1110

И нет необходимости в отдельной проверке на 1.

3 голосов
/ 28 июня 2009

объяснил здесь красиво

Также данное выражение рассматривает 0 как степень 2. Чтобы исправить это, используйте !(x & (x - 1)) && x; вместо.

1 голос
/ 27 октября 2014

Определяет, является ли целое число степенью 2 или нет. Если (x & (x-1)) равно нулю, то число равно степени 2.

Например, пусть x будет 8 (1000 в двоичном виде); затем x-1 = 7 (0111).

if    1000
  &   0111
---------------
      0000

Программа для демонстрации:

#include <stdio.h>

void main()
{
    int a = 8;
    if ((a&(a-1))==0)
    {
        printf("the bit is power of 2  \n");
    }
    else 
    {
        printf("the bit is not power of 2\n");
    }
}

Это выводит the bit is power of 2.

#include <stdio.h>

void main()
{
    int a = 7;
    if ((a&(a-1))==0)
    {
        printf("the bit is power of 2  \n");
    }
    else 
    {
        printf("the bit is not power of 2\n");
    }
}

Это выводит the bit is not power of 2.

0 голосов
/ 04 марта 2014

Следующая программа на C узнает, является ли число степенью 2, а также определит, какая из степеней 2, является число.

#include<stdio.h>
void main(void)
{
    unsigned int a;
    unsigned int count=0
    unsigned int check=1;
    unsigned int position=0;
    unsigned int temp;
    //get value of a
    for(i=0;i<sizeof(int)*8;i++)//no of bits depend on size of integer on that machine
    {
        temp = a&(check << i);
        if(temp)
        {
            position = i;
            count++;
        }
    }
    if(count == 1)
    {
        printf("%d is 2 to the power of %d",a,position);
    }
    else
    {
        printf("Not a power of 2");
    }
}

Есть и другие способы сделать это: - если число является степенью 2, в двоичном формате будет установлен только 1 бит

для примера 8 эквивалентно 0x1000, вычитая 1 из этого, мы получаем 0x0111.

Завершение операции с исходным номером (0x1000) дает 0.

если это так, число является степенью 2

    void IsPowerof2(int i)
    {
    if(!((i-1)&1))
    {
    printf("%d" is a power of 2, i);
    }
    }

другой способ может быть таким: -

Если мы возьмем дополнение числа, которое является степенью 2,

например, дополнение к 8, т.е. 0x1000, мы получаем 0x0111 и добавляем 1 к нему, мы получаем

то же число, если это так, это число является степенью 2

    void IsPowerof2(int i)
    {
    if(((~1+1)&i) == 1)
    {
    printf("%d" is a power of 2,i):
    }
    }                                                     
...