Какой самый простой способ проверить, является ли число степенью 2 в C ++? - PullRequest
78 голосов
/ 20 сентября 2008

Мне нужна такая функция:

// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true  is_power_of_2(3) => false
bool is_power_of_2(int n);

Кто-нибудь может подсказать, как я мог написать это? Можете ли вы сказать мне хороший веб-сайт, где можно найти такой алгоритм?

Ответы [ 16 ]

163 голосов
/ 20 сентября 2008

(n & (n - 1)) == 0 лучше. Однако обратите внимание, что он будет неверно возвращать true для n = 0, поэтому, если это возможно, вы захотите проверить это явно.

http://www.graphics.stanford.edu/~seander/bithacks.html имеет большой набор умных алгоритмов переворота битов, включая этот.

75 голосов
/ 20 сентября 2008

Для степени двойки будет установлен только один бит (для чисел без знака). Что-то вроде

bool powerOfTwo = !(x == 0) && !(x & (x - 1));

будет работать нормально; единица, меньшая, чем степень двойки, равна единице в младших битах, поэтому значение И должно быть равно 0 в битах.

Поскольку я принимал числа без знака, тест == 0 (который я изначально забыл, извините) является адекватным. Вам может потребоваться тест> 0, если вы используете целые числа со знаком.

46 голосов
/ 20 сентября 2008

Сила двух в двоичном виде выглядит так:

1: 0001
2: 0010
4: 0100
8: 1000

Обратите внимание, что всегда установлен ровно 1 бит. Единственное исключение - целое число со знаком. например 8-разрядное целое число со знаком со значением -128 выглядит следующим образом:

10000000

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

bool is_power_of_2(int x) {
    return x > 0 && !(x & (x−1));
}

Для получения дополнительной информации см. здесь .

12 голосов
/ 20 января 2016

Подход № 1:

Разделите число на 2, чтобы проверить это.

Сложность времени: O (log2n).

Подход № 2:

Побитовое И номер с только что предыдущим номером должен быть равен нулю.

Пример: Число = 8 Двоичный 8: 0 0 0 0 Двоичное число 7: 0 1 1 1 и побитовое И обоих чисел равно 0 0 0 0 = 0.

Сложность времени: O (1).

Подход № 3:

Побитовое XOR число с только что предыдущим номером должно быть суммой обоих чисел.

Пример: Число = 8 Двоичный 8: 0 0 0 0 Двоичное число 7: 0 1 1 1 и битовое XOR обоих чисел равно 1 1 1 1 = 15.

Сложность времени: O (1).

http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html

7 голосов
/ 20 сентября 2008
bool is_power_of_2(int i) {
    if ( i <= 0 ) {
        return 0;
    }
    return ! (i & (i-1));
}
5 голосов
/ 29 мая 2016

для любой степени 2 также имеет место следующее.

п & (- п) == п

ПРИМЕЧАНИЕ: условие истинно для n = 0, хотя оно не является степенью 2.
Причина, по которой это работает:
-n является дополнением 2s от n. -n будет иметь каждый бит слева от крайнего правого установленного бита n по сравнению с n. Для степеней 2 есть только один установленный бит.

3 голосов
/ 16 октября 2016
return n > 0 && 0 == (1 << 30) % n;
2 голосов
/ 20 сентября 2016

Какой самый простой способ проверить, является ли число степенью 2 в C ++?

Если у вас современный процессор Intel с инструкциями по обработке битов , то вы можете выполнить следующее. Он пропускает прямой код C / C ++, потому что другие уже ответили на него, но он вам нужен, если BMI недоступен или не включен.

bool IsPowerOf2_32(uint32_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
    return !!((x > 0) && _blsr_u32(x));
#endif
    // Fallback to C/C++ code
}

bool IsPowerOf2_64(uint64_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
    return !!((x > 0) && _blsr_u64(x));
#endif
    // Fallback to C/C++ code
}

Поддержка BMI сигналов GCC, ICC и Clang с __BMI__. Он доступен в компиляторах Microsoft в Visual Studio 2015 и более поздних версиях, когда AVX2 доступен и включен . Сведения о заголовках см. В Файлы заголовков для встроенных функций SIMD .

.

Обычно я защищаю _blsr_u64 с _LP64_ в случае компиляции на i686. Clang нуждается в небольшом обходном пути, потому что он использует несколько иной внутренний символ nam:

#if defined(__GNUC__) && defined(__BMI__)
# if defined(__clang__)
#  ifndef _tzcnt_u32
#   define _tzcnt_u32(x) __tzcnt_u32(x)
#  endif
#  ifndef _blsr_u32
#    define  _blsr_u32(x)  __blsr_u32(x)
#  endif
#  ifdef __x86_64__
#   ifndef _tzcnt_u64
#    define _tzcnt_u64(x) __tzcnt_u64(x)
#   endif
#   ifndef _blsr_u64
#     define  _blsr_u64(x)  __blsr_u64(x)
#   endif
#  endif  // x86_64
# endif  // Clang
#endif  // GNUC and BMI

Можете ли вы сказать мне хороший веб-сайт, где можно найти такой алгоритм?

Этот сайт часто цитируется: Bit Twiddling Hacks .

2 голосов
/ 12 октября 2015

Следующий будет быстрее, чем ответ с наибольшим количеством голосов из-за логического короткого замыкания и того, что сравнение идет медленно

int isPowerOfTwo(unsigned int x)
{
  return x && !(x & (x – 1));
}

Если вы знаете, что x не может быть 0, тогда

int isPowerOfTwo(unsigned int x)
{
  return !(x & (x – 1));
}
1 голос
/ 20 марта 2019

Это самый быстрый:

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