다음과 같은 기능이 필요합니다.
// 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);
누구든지 내가 이것을 어떻게 쓸 수 있는지 제안 할 수 있습니까? 이런 종류의 알고리즘을 찾을 수있는 좋은 웹 사이트를 알려주시겠습니까?
다음과 같은 기능이 필요합니다.
// 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);
누구든지 내가 이것을 어떻게 쓸 수 있는지 제안 할 수 있습니까? 이런 종류의 알고리즘을 찾을 수있는 좋은 웹 사이트를 알려주시겠습니까?
답변:
(n & (n - 1)) == 0
최고. 그러나 n = 0에 대해 부정확하게 true를 반환하므로 가능하면 명시 적으로 확인하는 것이 좋습니다.
http://www.graphics.stanford.edu/~seander/bithacks.html 에는 이것을 포함하여 영리한 비트 트위들 링 알고리즘이 많이 있습니다.
(n>0 && ((n & (n-1)) == 0))
n && !(n & (n - 1))
답변 내 링크로 표시됩니다.
n & !(n & (n - 1))
. 비트 AND &
(논리적 and &&
아님)에 주목하십시오 . 비트 연산자는 단락을 구현하지 않으므로 코드가 분기되지 않습니다. 이는 분기 오 예측 가능성이 있고 표현식 (즉, !(n & (n - 1))
) 의 rhs를 계산하는 것이 저렴한 상황에서 바람직 합니다.
!
는 논리 연산자이므로의 값은 !(n & (n - 1))
부울이됩니다. 비트 AND 연산자에 부울과 숫자를 지정할 수 있습니까? 그렇다면 괜찮아 보입니다.
2의 거듭 제곱은 하나의 비트 세트 (부호없는 숫자의 경우) 만 갖습니다. 같은 것
bool powerOfTwo = !(x == 0) && !(x & (x - 1));
잘 작동합니다. 2의 거듭 제곱보다 작은 것은 하위 비트에서 모두 1이므로 AND는 비트 단위로 0이어야합니다.
서명되지 않은 숫자를 가정하고 있었기 때문에 == 0 테스트 (원래 잊고 있었지만 죄송합니다)가 적절합니다. 부호있는 정수를 사용하는 경우> 0 테스트를 원할 수 있습니다.
접근법 # 1 :
그것을 확인하기 위해 은밀하게 숫자를 2로 나눕니다.
시간 복잡도 : O (log2n).
접근법 # 2 :
비트 AND 바로 이전 숫자가있는 숫자는 0과 같아야합니다.
예 : Number = 8 Binary of 8 : 1 0 0 0 Binary of 7 : 0 1 1 1이고 두 숫자의 비트 AND는 0 0 0 0 = 0입니다.
시간 복잡도 : O (1).
접근법 # 3 :
비트 단위 XOR 이전 숫자가있는 숫자는 두 숫자의 합이어야합니다.
예 : Number = 8 Binary of 8 : 1 0 0 0 Binary of 7:01 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
2의 거듭 제곱에 대해 다음도 적용됩니다.
참고 : 조건은 2의 거듭 제곱이 아니지만 n = 0에 대해 참입니다.
이것이 작동하는 이유는 다음과 같습니다.
-n은 n의 2s 보수입니다. -n은 n에 비해 가장 오른쪽에 설정된 비트의 왼쪽에있는 모든 비트를 뒤집습니다. 2의 거듭 제곱의 경우 한 세트 비트 만 있습니다.
GCC를 사용하는 경우 이것이 아마도 가장 빠를 것입니다. POPCNT cpu 명령어와 하나의 비교 만 사용합니다. 2의 거듭 제곱에 대한 이진 표현은 항상 하나의 비트 만 설정하고 다른 비트는 항상 0입니다. 그래서 우리는 POPCNT로 설정된 비트의 수를 세고 만약 1과 같으면 그 수는 2의 거듭 제곱입니다. 가능한 더 빠른 방법은 없다고 생각합니다. 한 번 이해했다면 매우 간단합니다.
if(1==__builtin_popcount(n))
i && !(i & (i - 1)))
경우 gcc에서 네이티브 어셈블리 POPCNT 명령을 활성화 할 때에도 내 컴퓨터 에서 테스트 가 약 10 % 더 빠릅니다.
C ++ 20에는 std::ispow2
직접 구현할 필요가없는 경우 정확히 이러한 목적으로 사용할 수있는 것이 있습니다.
#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));
C ++에서 숫자가 2의 거듭 제곱인지 테스트하는 가장 간단한 방법은 무엇입니까?
Bit Manipulation Instructions 가있는 최신 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__
. AVX2를 사용할 수 있고 활성화 된 경우 Visual Studio 2015 이상의 Microsoft 컴파일러에서 사용할 수 있습니다. 필요한 헤더는 SIMD 내장 함수의 헤더 파일을 참조하세요 .
나는 일반적 으로 i686에서 컴파일하는 경우를 _blsr_u64
사용하여 보호합니다 _LP64_
. Clang은 약간 다른 고유 기호 이름을 사용하기 때문에 약간의 해결 방법이 필요합니다.
#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 .
이것은 가장 빠르거나 짧은 방법은 아니지만 매우 읽기 쉽다고 생각합니다. 그래서 나는 다음과 같이 할 것입니다.
bool is_power_of_2(int n)
int bitCounter=0;
while(n) {
if ((n & 1) == 1) {
++bitCounter;
}
n >>= 1;
}
return (bitCounter == 1);
}
바이너리는 2의 거듭 제곱을 기반으로하기 때문에 작동합니다. 비트 세트가 하나 뿐인 숫자는 2의 거듭 제곱이어야합니다.
C ++를 통해 가능합니다.
int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}
log2
, 으로 인해 확실히 빠르지 않으며 작동한다는 증거는 설명하기가 쉽지 않습니다 (정확히 반올림 오류로 인해 잡힐 수 있습니까?). 또한 불필요하게 if..return..else..return
. 접는 것이 잘못된 이유return x==(double)y;
? bool
anyayws 를 반환해야합니다 . IMO는 정말로 고수하고 싶다면 삼항 연산자조차 더 명확 할 것 int
입니다.
다음은 T-SQL (SQL Server)의 비트 시프트 방법입니다.
SELECT CASE WHEN @X>0 AND (@X) & (@X-1)=0 THEN 1 ELSE 0 END AS IsPowerOfTwo
로그를 4 번 수행하는 것보다 훨씬 빠릅니다 (첫 번째는 10 진수 결과를 얻고 두 번째는 정수를 설정하고 비교).