Binary Exponentiation
Typical Exponentiation
Let's say you wanted to calculate the large power of a number modulo another such as
The most naive way to do this would be to multiply by itself times and then take the remainder when divided by , aka the last digits. However, this technique quickly becomes unmanageable, especially since has digits, which would lead to a lot of work and the opportunity to make a lot of mistakes. Instead, we could work smarter, not harder.
The next way we could augment this process is by realizing that after each successive multiplication, we could take the intermediate product modulo . For instance, we would first have . After this, we would have , but we can ignore everything but the last digits and simply take the as our product moving forward. By continuing this strategy, we will constantly stay with small numbers and not have to deal with digit monstrosities. However, this still involves us doing multiplications to get from to . As the exponent grows even larger, it would become infeasible for humans to do it by hand.
While computers can solve these problems easily, even computers have their limitations. If the computer has to do thousands of these calculations and take powers that go up to the hundreds of millions, this strategy quickly grows infeasible as well.
However, there is a solution that can drastically speed up this calculation for large numbers known as binary exponentiation. Binary exponentiation takes advantage of the fact that we can square numbers in a single operation by simply multiplying it with itself, which doubles the exponent.
Applying Squaring
Let's say that the power we wanted to calculate was . While we could multiply with itself times, let's use squaring. We can first calculate . Then, rather than multiplying by twice, we can instead square in a single operation to get
Finally, we can square this number to get
By using squaring, we were able to reduce our multiplication from steps to only . While one may say that this may have made the operation harder since we had to square very large numbers, if we had even larger exponents and were also taking the values modulo something, the benefits of this method quickly become apparent as the number of multiplications required would actually be logarithmic when compared to the exponent. Going all the way up to something like the th exponent would only require operations, compared to the from before.
However, this very simple trick only works at the moment with exponents that are powers of . However, this is where the binary part of binary exponentiation comes in.
Binary
If you aren't familiar with the concept of other number bases, please look at this explanation from Better Explained that covers it well.
Now that you are familiar with number bases, binary is another word for base , where each digit in a number can be either or and represents a power of . You may have heard about binary in other contexts such as describing things that only have options or with computers since binary is used to represent all numbers for a computer.
Let's look at a few examples to make sure we are comfortable with binary, but feel free to skip to the next section if you are already comfortable.
Example
Express the binary number in base .
We can do this by looking at each digit from right to left and using those to see which powers of are present in our number. Since the first two digits on the right are both s, we know that and are present in our number. Since the third digit is a , is not. However, the next three are, so the total sum would be
Example
Express the number in binary.
We can do this by first looking for the largest power of present in . The powers of are Since but , we know that is the largest power of present. We can keep note that is present in the number and move on by subtracting from . We are left with and we have to now find the largest power of present in that. The answer is , and after subtracting that we are left with . We know that the powers of present are , which corresponds to the number , since all of the correct powers of are represented there.
Full Binary Exponentiation
Now that we have a grasp on binary, we can move on to what exactly binary exponentiation is. The idea behind the technique is that we can break up the exponent into its binary representation and then use those corresponding powers of s in our calculation. For instance, let's say we wanted to calculate the following:
We can first express our exponent, , in binary, or as sums of powers of . We can quickly get that it is
We can then plug this representation back into our original equation to obtain:
Rewriting this with laws of exponents, we obtain the following result:
However, remember what we said before about exponents that were powers of . We can apply squaring to easily calculate all of those powers required in just operations. Then, we can simply multiply together the results to obtain the final answer in much less than operations.
Calculating the Powers
Final Result
Since those numbers were huge, a more reasonable calculation might be to instead calculate
This could be done the mostly the same way, but you have to instead take each intermediate result mod .
Calculating the Powers
Final Result
And that's pretty much the entire method! Next up, we'll go over the advantages of this algorithm and then some of the applications for such huge exponents.
Big O Notation
For those not comfortable with big O notation from computer science, feel free to skip this section. But for those interested, it is essentially a measure of how the number of operations required in a calculation scale as the input size changes. Check out this article for more details if you're interested. It's a topic that is very important for analyzing the runtime of computer algorithms, but its core ideas can be applied in other subject areas.
For those who know what it is, you may have realized that the naive algorithm for calculating exponents runs in linear time. However, the binary exponentiation method runs in time, which is a massive improvement as increases. This is because the number of digits in the binary representation of a number is approximately equal to .
Advantage Over Naive Method
One could appreciate the significant advantages of using this algorithm when calculating something like .
The naive method would require around operations since you would have to multiply by that many times. However, the binary representation of is , which is only digits long. This means that you would have to calculate only powers of (with two of them being and ). Then, you would only need to multiply of those numbers, which would correspond to the s in the binary representation. This totals only operations compared to the almost from before.
Applications
Modular Inverses
The first application is for calculating modular inverses. In the short future, I'll add a post that goes over this topic in depth, but essentially there's a formula that allows you to calculate the modular inverse of a number mod .
For extremely large , especially when is prime, binary exponentiation is almost a necessity to do the operations with enough speed.
Fibonacci Relation
However, this idea of binary exponentiation does not just apply to numbers; it can also be applied to ideas like matrices. For instance, it can even be used to calculate the Fibonacci numbers! If you're not familiar with matrices, and how they can be multiplied or used to represent linear systems, I would highly recommend checking it out since they can be really cool.
For those unfamiliar with the Fibonacci numbers, they are a sequence of integers such that represents the th Fibonacci numbers. We define and , and then we use the recurrence relation
Essentialy, each next term is the sum of the previous terms. The sequence goes like this:
We can actually express this with the following equation:
To dissect how this matrix equation works, we can break it down into its component linear equations:
Both of these equations perfectly describe how the Fibonacci sequence is generated, showing how the matrix equation encodes the linear recurrence present in the system. The reason why this is so powerful is that we can continuously multiply these matrices to obtain higher values in the Fibonacci sequence.
In general, we can do the following:
This gives us a method using matrix exponentiation to calculate the th Fibonacci number. However, with the power of binary exponentiation, we can calculate this exponent quickly, making calculating something like the th Fibonacci number relatively trivial. The same process of binary exponentiation can be used making this a relatively flexible technique.
Conclusion
Overall, binary exponentiation is a pretty powerful technique to both do hand computations quickly and to speed up computer algorithms. It can be applied to pretty much any mathematical structure that has exponentiation as well, including real numbers, complex numbers, and matrices, two of which we saw above.
Side Note: Implementation in Programming
As a quick side note, we could do the following to implement this algorithm in code (the code is in Java, but it is easily expandable to other languages). I'm not going to go over exactly how the code works as of now, but I might add it in the future.
long binaryExpo(int base, int exponent) {
long result = 1;
long currPower = base;
while(exponent > 0) {
if (exponent % 2 > 0) {
result = result * currPower;
}
currPower = currPower * base;
exponent /= 2;
}
return result;
}
We could optimize this program with bitwise operations as following (although a good compiler would probably automatically substitute these in). This method might appear more intuitive for those familar with the binary operations utilized, since it more clearly shows how you're analyzing each binary digit of the exponent.
long binaryExpo(int base, int exponent) {
long result = 1;
long currPower = base;
while(exponent > 0) {
if (exponent & 1 > 0) {
result = result * currPower;
}
currPower = currPower * base;
exponent >>= 1;
}
return result;
}