it-roy-ru.com

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

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

// 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);

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

72
Ant

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

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

156
Anonymous

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

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

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

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

72
Adam Wright

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

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));
}

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

44
Matt Howells

Подход № 1:

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

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

Подход № 2:

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

Пример: Number = 8 Двоичное число 8: 1 0 0 0 Двоичное число 7: 0 1 1 1 и битовое И для обоих чисел равно 0 0 0 0 = 0.

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

Подход № 3:

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

Пример: Number = 8 Двоичное число 8: 1 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

12
Raj Dixit
bool is_power_of_2(int i) {
    if ( i <= 0 ) {
        return 0;
    }
    return ! (i & (i-1));
}
5
Rob Wells

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

п & (- п) == п

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

3
FReeze FRancis
return n > 0 && 0 == (1 << 30) % n;
3
Yuxiang Zhang

Какой самый простой способ проверить, является ли число степенью 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
}

GCC, ICC и Clang сигнализируют о поддержке BMI с помощью __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
jww

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

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

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

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

Это не самый быстрый или короткий путь, но я думаю, что он очень удобочитаемый. Так что я бы сделал что-то вроде этого:

bool is_power_of_2(int n)
  int bitCounter=0;
  while(n) {
    if ((n & 1) == 1) {
      ++bitCounter;
    }
    n >>= 1;
  }
  return (bitCounter == 1);
}

Это работает, так как двоичный код основан на двух степенях. Любое число, для которого установлен только один бит, должно быть степенью двойки.

1
Jere.Jones

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

if(1==__builtin_popcount(n))
1
F10PPY

Вот другой метод, в данном случае использующий | вместо &:

bool is_power_of_2(int x) {
    return x > 0 && (x<<1 == (x|(x-1)) +1));
}
0
Chethan

Можно через с ++

int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}
0
Jay Ponkia