Как проверить, является ли число степенью 2
сегодня мне нужен простой алгоритм для проверки, является ли число степенью числа 2.
алгоритм должен быть:
- простой
- необходимая для любого
ulongзначение.
Я придумал такой простой алгоритм:
private bool IsPowerOfTwo(ulong number)
{
if (number == 0)
return false;
for (ulong power = 1; power > 0; power = power << 1)
{
// This for loop used shifting for powers of 2, meaning
// that the value will become 0 after the last shift
// (from binary 1000...0000 to 0000...0000) then, the 'for'
// loop will break out.
if (power == number)
return true;
if (power > number)
return false;
}
return false;
}
но потом я подумал, как насчет проверки, если log2 x - Это точно круглое число? Но когда я проверил 2^63+1,Math.Log вернулся ровно 63 из-за округлений. Так я проверил, если 2 к мощность 63 равна исходному числу - и это так, потому что расчет производится в double s и не в точных числах:
private bool IsPowerOfTwo_2(ulong number)
{
double log = Math.Log(number, 2);
double pow = Math.Pow(2, Math.Round(log));
return pow == number;
}
вернуть true для данного неправильного значения:9223372036854775809.
есть ли лучший алгоритм?
21 ответов:
есть простой трюк для этой проблемы:
bool IsPowerOfTwo(ulong x) { return (x & (x - 1)) == 0; }обратите внимание, эта функция будет отчет
trueна0, который не является силой2. Если вы хотите исключить это, вот как:bool IsPowerOfTwo(ulong x) { return (x != 0) && ((x & (x - 1)) == 0); }объяснение
прежде всего побитовый двоичный оператор & из определения MSDN:
бинарные & операторы предопределены для интегральных типов и bool. Для целочисленные типы, & вычисляет логический побитовый И его операндов. Для операндов bool & вычисляет логическое и его операндов; что результат true если и только если оба ее операнда истинны.
теперь давайте посмотрим, как все это происходит:
функция возвращает логическое значение (true / false) и принимает один входящий параметр типа unsigned long (x, в данном случае). Давайте для простоты предположим, что кто-то передал значение 4 и вызвал функцию типа Итак:
bool b = IsPowerOfTwo(4)теперь мы заменяем каждое вхождение x на 4:
return (4 != 0) && ((4 & (4-1)) == 0);Ну мы уже знаем, что 4 != 0 evals к истине, до сих пор так хорошо. Но как насчет:
((4 & (4-1)) == 0)это, конечно, переводится так:
((4 & 3) == 0)но что же такое
4&3?двоичное представление 4 равно 100, а двоичное представление 3-011 (помните, что & принимает двоичное представление этих чисел). Так что мы есть:
100 = 4 011 = 3представьте, что эти значения складываются так же, как элементарное сложение. Элемент
&оператор говорит, что если оба значения равны 1, то результат 1, иначе 0. Так что1 & 1 = 1,1 & 0 = 0,0 & 0 = 0и0 & 1 = 0. Итак, мы делаем математику:100 011 ---- 000результат просто 0. Итак, мы возвращаемся и смотрим на то, что теперь переводит наше заявление о возврате:
return (4 != 0) && ((4 & 3) == 0);что переводится сейчас к:
return true && (0 == 0);return true && true;мы все это знаем
true && trueпростоtrue, и это показывает, что для нашего примера 4-это степень 2.
некоторые сайты, которые документируют и объясняют это и другие битные хаки:
- http://graphics.stanford.edu / ~seander/bithacks.html
(http://graphics.stanford.edu/~seander / bithacks. html#DetermineIfPowerOf2)- http://bits.stephan-brumme.com/
(http://bits.stephan-brumme.com/isPowerOfTwo.html)и дедушка их,книга "Восторг хакера" Генри Уоррена-младшего:
Как страница Шона Андерсона объясняет, выражение
((x & (x - 1)) == 0)неверно указывает, что 0-это степень 2. Он предлагает использовать:(!(x & (x - 1)) && x)чтобы исправить эту проблему.
недавно я написал об этом статью на сайте http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/. он охватывает бит подсчета, Как правильно использовать логарифмы, классический " x && !(x & (x - 1))" проверка и другие.
вот простой C++ устранение:
bool IsPowerOfTwo( unsigned int i ) { return std::bitset<32>(i).count() == 1; }
bool IsPowerOfTwo(int n) { if (n > 1) { while (n%2 == 0) { n >>= 1; } } return n == 1; }и вот общий алгоритм для выяснения, является ли число силой другого числа.
bool IsPowerOf(int n,int b) { if (n > 1) { while (n % b == 0) { n /= b; } } return n == 1; }
после публикации вопроса я подумал о следующем решении:
мы должны проверить, если точно один из двоичных цифр является одним. Поэтому мы просто сдвигаем число вправо на одну цифру за раз и возвращаем
trueесли он равен 1. Если в какой-то момент мы приходим на нечетное число ((number & 1) == 1), мы знаем, что в результатеfalse. Это оказалось (с использованием бенчмарка) немного быстрее, чем исходный метод для (больших) истинных значений и намного быстрее для ложных или малых ценности.private static bool IsPowerOfTwo(ulong number) { while (number != 0) { if (number == 1) return true; if ((number & 1) == 1) // number is an odd number and not 1 - so it's not a power of two. return false; number = number >> 1; } return false; }
конечно, решение Грега намного лучше.
следующее дополнение к принятому ответу может быть полезно для некоторых людей:
степень двойки, выраженная в двоичном формате, всегда будет выглядеть как 1, за которым следует n нулей где n больше или равно 0. Например:
Decimal Binary 1 1 (1 followed by 0 zero) 2 10 (1 followed by 1 zero) 4 100 (1 followed by 2 zeroes) 8 1000 (1 followed by 3 zeroes) . . . . . .и так далее.
когда мы вычитаем
1от такого рода чисел они становятся 0, а затем n единиц и снова n такое же, как и выше. Например:Decimal Binary 1 - 1 = 0 0 (0 followed by 0 one) 2 - 1 = 1 01 (0 followed by 1 one) 4 - 1 = 3 011 (0 followed by 2 ones) 8 - 1 = 7 0111 (0 followed by 3 ones) . . . . . .и так на.
подходим к сути
что происходит, когда мы делаем побитовое и из нескольких
x, который является мощность 2, иx - 1?один из
xвыравнивается с нулемx - 1и все нулиxувязан сx - 1, вызывая побитовое и привести к 0. и вот как у нас есть ответ на одну строку, упомянутый выше, является правильным.
далее добавление к красоте принятого ответа выше -
Итак, у нас есть собственность в нашем распоряжении сейчас:
когда мы вычитаем 1 из любого числа, то в двоичном представлении правый 1 станет 0 и все нули перед правый 1 теперь станет 1
одно удивительное использование этого свойства заключается в выяснении -сколько единиц присутствует в двоичном представлении данного числа? короткий и сладкий код, чтобы сделать это для данного целого числа
x- это:byte count = 0; for ( ; x != 0; x &= (x - 1)) count++; Console.Write("Total ones in the binary representation of x = {0}", count);
другой аспект чисел, который может быть доказан из концепции, объясненной выше, является " может ли каждое положительное число быть представлено как сумма степеней 2?".
да, каждое положительное число может быть представлено как сумма степеней 2. Для любого числа возьмите его двоичное представление. Пример: возьмите номер
501.The binary of 501 is 111110101 Because 111110101 = 100000000 + 10000000 + 1000000 + 100000 + 1000 + 000 + 100 + 00 + 1 we have 501 = 256 + 128 + 64 + 32 + 16 + 0 + 4 + 0 + 1
найти, если данное число является степенью числа 2.
#include <math.h> int main(void) { int n,logval,powval; printf("Enter a number to find whether it is s power of 2\n"); scanf("%d",&n); logval=log(n)/log(2); powval=pow(2,logval); if(powval==n) printf("The number is a power of 2"); else printf("The number is not a power of 2"); getch(); return 0; }
bool isPowerOfTwo(int x_) { register int bitpos, bitpos2; asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_)); asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_)); return bitpos > 0 && bitpos == bitpos2; }
int isPowerOfTwo(unsigned int x) { return ((x != 0) && ((x & (~x + 1)) == x)); }Это очень быстро. Она занимает около 6 минут и 43 секунд, чтобы проверить все 2^32 чисел.
return ((x != 0) && !(x & (x - 1)));если
xэто сила двух, его одинокий 1 бит находится в положенииn. Это значитx – 10 в должностиn. Чтобы понять почему, вспомните, как работает двоичное вычитание. При вычитании 1 изx, заимствование распространяется до самого положенияn; битnстановится 0 и все младшие биты стали 1. Теперь, так какxне имеет 1 бит общего сx – 1,x & (x – 1)0, а!(x & (x – 1))- это правда.
число кратно 2, если он содержит только 1 бит. Мы можем использовать это свойство и универсальную функцию
countSetBitsчтобы узнать, является ли число силой 2 или нет.Это программа на C++:
int countSetBits(int n) { int c = 0; while(n) { c += 1; n = n & (n-1); } return c; } bool isPowerOfTwo(int n) { return (countSetBits(n)==1); } int main() { int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70}; for(i=0; i<sizeof(val)/sizeof(val[0]); i++) printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i])); return 0; }нам не нужно явно проверять, что 0 является силой 2, так как он также возвращает False для 0.
выход
Num:0 Set Bits:0 is power of two: 0 Num:1 Set Bits:1 is power of two: 1 Num:2 Set Bits:1 is power of two: 1 Num:3 Set Bits:2 is power of two: 0 Num:4 Set Bits:1 is power of two: 1 Num:5 Set Bits:2 is power of two: 0 Num:15 Set Bits:4 is power of two: 0 Num:16 Set Bits:1 is power of two: 1 Num:22 Set Bits:3 is power of two: 0 Num:32 Set Bits:1 is power of two: 1 Num:38 Set Bits:3 is power of two: 0 Num:64 Set Bits:1 is power of two: 1 Num:70 Set Bits:3 is power of two: 0
вот еще один метод, который я разработал, в этом случае используя
|вместо&:bool is_power_of_2(ulong x) { if(x == (1 << (sizeof(ulong)*8 -1) ) return true; return (x > 0) && (x<<1 == (x|(x-1)) +1)); }
улучшение ответа @user134548, без бит арифметики:
public static bool IsPowerOfTwo(ulong n) { if (n % 2 != 0) return false; // is odd (can't be power of 2) double exp = Math.Log(n, 2); if (exp != Math.Floor(exp)) return false; // if exp is not integer, n can't be power return Math.Pow(2, exp) == n; }это прекрасно работает для:
IsPowerOfTwo(9223372036854775809)
пример
0000 0001 Yes 0001 0001 No
используя битовую маску, разделить
NUMпеременной в двоичном
IF R > 0 AND L > 0: Return FALSEиначе
NUMстановится ненулевым
IF NUM = 1: Return TRUEв противном случае, перейдите к шагу 1
сложности
время ~
O(log(d))здесьdэто количество двоичных цифр
для любой степени 2 также выполняется следующее.
n&(-n)==n
примечание: не для n=0 , поэтому нужно проверить его
Причина, почему это работает:
-п-2S дополняют Н. -N будет иметь каждый бит слева от установить крайний правый бит из N переворачивается по сравнению с н. Для полномочия 2 существует только один бит.
эта программа в Ява возвращает "true", если число является степенью числа 2, и возвращает значение "false", если не является степенью числа 2
// To check if the given number is power of 2 import java.util.Scanner; public class PowerOfTwo { int n; void solve() { while(true) { // To eleminate the odd numbers if((n%2)!= 0){ System.out.println("false"); break; } // Tracing the number back till 2 n = n/2; // 2/2 gives one so condition should be 1 if(n == 1) { System.out.println("true"); break; } } } public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); PowerOfTwo obj = new PowerOfTwo(); obj.n = in.nextInt(); obj.solve(); } } OUTPUT : 34 false 16 true
Comments