1. Overview

In this tutorial, we’ll discuss the problem of checking whether a number is a power of two.

First, we’ll define the problem. Then we’ll give an example to explain it.

Finally, we’ll present three different approaches to solving this problem.

2. Defining the Problem

Given the positive integer N, we need to check whether it’s a power of two or not.

Let’s take a look at the following examples:

  • N = 1 \Rightarrow Power of two (2^0).
  • N = 8 \Rightarrow Power of two (2^3).
  • N = 15 \Rightarrow Not a power of two.
  • N = 0 \Rightarrow Not a power of two.

3. Loop Approach

3.1. Main Idea

When we check the power of two numbers, we can see that they’re written in binary representation, in a format like 1000....00 (one followed by zeros). So the main idea in this approach is to keep removing zeros from the end of the number until we reach a one.

Once we reach a one, we check whether the number becomes equal to 1 after removing all the trailing zeros. If so, it means the given number is a power of two.

3.2. Algorithm

Let’s take a look at the implementation:

algorithm isPowerOfTwoUsingLoop(N):
    // INPUT
    //    N = the number to check
    // OUTPUT
    //    Returns true if N is a power of 2, false otherwise
    
    while N > 0 and N mod 2 = 0:
        N <- N / 2
    
    if N = 1:
        return true
    else:
        return false

Initially, as long as N is even and greater than zero, it means there’s a zero at the end of the binary representation of N. In this case, we divide N by two to shift the binary representation to the right (remove the trailing zero). Once one of the previous conditions becomes false, we’ll break out of the loop.

In the end, if N becomes equal to 1, it means the given number is a power of two, so we return true. Otherwise, we return false.

3.3. Complexity

The complexity of this algorithm is \boldsymbol{O(Log_2(N))} , where N is the given number. The reason behind this complexity is that we’ll iterate over all the bits of the given number. The number of bits is equal to Log_2(N).

4. Binary Search Approach

4.1. Main Idea

The main idea in this approach is to use binary search to find whether a power of two that is equal to N exists. Furthermore, the search will be on the exponential part of the number. So if the current power of two is less than N, we’ll look for a bigger one.

On the other hand, if the current power of two is greater than N, we’ll try to find a smaller power. Once we find a power X that makes N = 2^X, we’ll return true.

However, if the binary search ends and we don’t find any power of two equal to N, that means N is not a power of two.

4.2. Algorithm

Let’s take a look at the implementation:

algorithm isPowerOfTwoUsingBinarySearch(N):
    // INPUT
    //    N = the number to check
    // OUTPUT
    //    Returns true if N is a power of 2, false otherwise
    
    low <- 0
    high <- log2(N)
    
    while low <= high:
        mid <- (low + high) / 2
        if 2^mid = N:
            return true
        else if 2^mid < N:
            low <- mid + 1
        else:
            high <- mid - 1
    
    return false

Initially, we declare the boundaries of binary search. low is the minimum power possible, and it’s equal to zero. Conversely, high is the maximum power possible, and it’s equal to Log_2(N) (number of bits in N).

Next, as long as the low boundary is less than or equal to the high boundary, we’ll take the middle as the exponential part of the number and check whether the generated power of two is equal to N. If so, we’ll return true. Otherwise, we’ll check if the current number is less than N. In this case, we’ll try to look for bigger power. If not, we’ll look for a smaller power.

Finally, if we don’t find any power of two equal to N, we’ll return false.

4.3. Complexity

The complexity of this algorithm is \boldsymbol{O(Log_2(Log_2(N)))} , where N is the given number.

The complexity here is equal to the complexity of the binary search, which is Log_2(M), and M here is Log_2(N) because we have Log_2(N) possible powers we want to check.

5. Bitmask Approach

5.1. Main Idea

The main idea here is that we’ll get the advantage of the binary representation of N. Furthermore, the binary representation of any power of two numbers is in a format like 1000...000. So if we delete one from a power of two, it becomes something like 0111...111. Then if we take the bitwise-and operation between N and N - 1, the result should be equal to zero if N is a power of two. Otherwise, it’s not.

5.2. Algorithm

Let’s take a look at the implementation:

algorithm isPowerOfTwoUsingBitmask(N):
    // INPUT
    //    N = the number to check
    // OUTPUT
    //    Returns true if N is a power of 2, false otherwise
    
    if N > 0 and (N bitwise-and (N - 1) = 0):
        return true
    else:
        return false

We check if N is greater than zero, since the smallest power of two is equal to one, and if the bitwise-and operation between N and N - 1 is equal to zero. If so, that means N is a power of two. Otherwise, it’s not a power of two.

5.3. Complexity

The complexity of this algorithm is \boldsymbol{O(1)} because we’re only doing one operation, which is the bitwise-and operation.

6. Conclusion

In this article, we presented the problem of checking whether a number is a power of two or not.

First, we provided an example to explain the problem. Then we gave three different approaches to solving this problem. Finally, we walked through their implementations, with each approach having a better time complexity than the previous one.