이 글에서는 비교적 간단한 방법을 사용해 주어진 숫자가 8의 거듭제곱인지 판별하는 방법을 알아보겠습니다. 예를 들어 4096이라는 숫자가 입력되면, 이는 8⁴이므로 프로그램은 true를 반환합니다.
핵심 아이디어
판별 방식은 매우 간단합니다. 바로 log₈(num) 값을 계산하는 것입니다. 만약 이 로그 값이 정수라면, 그 숫자는 8의 거듭제곱입니다.
여기서 로그 밑 변환 공식을 활용합니다. 즉, log₈(n)은 log(n)/log(8)과 같습니다. 계산 결과가 부동소수점 오차를 가질 수 있으므로, cmath 헤더의 trunc() 함수를 사용해 해당 double 값에서 가장 가까운 정수(소수점 이하 버림)를 구한 뒤, 원래 값과의 차이가 아주 작은 임계값(예: 0.000001)보다 작은지 검사합니다.
예제 코드
#include <iostream>
#include <cmath>
using namespace std;
bool isPowerOfEight(int n) {
double val = log(n) / log(8); // 밑이 8인 로그값 계산
return (val - trunc(val) < 0.000001);
}
int main() {
int number = 4096;
if(isPowerOfEight(number)) {
cout << number << " is power of 8";
} else {
cout << number << " is not power of 8";
}
}실행 결과
4096 is power of 8
코드 설명
isPowerOfEight 함수는 인자로 받은 정수 n에 대해 log(n)/log(8)을 계산하여 밑이 8인 로그값을 구합니다. 이 값이 정확히 정수라면 n은 8의 거듭제곱입니다. 다만 부동소수점 연산 특성상 미세한 오차가 발생할 수 있기 때문에, trunc(val)로 소수점 이하를 버린 정수 부분과의 차이가 0.000001 미만인지 확인하여 안정적으로 판별합니다.
참고로 1(=8⁰)도 8의 거듭제곱에 포함되며, 위 방식으로 정상적으로 true가 반환됩니다. 반면 0이나 음수는 로그를 정의할 수 없어 별도의 예외 처리가 필요할 수 있습니다.