The outer loop has a loop variable that is always a power of 2. The outer loop will make 1+⌊log2⌋ iterations.
Per iteration of the outer loop, the inner loop's body is executed as many times as the value of . So, in total, the number of executions of that inner body is expressed by the following sum:
20 + 21 + ... + 2⌊log2⌋
This is a geometric series. This can be written as a closed-form formula:
(1 − 21 + ⌊log2⌋) / (1 − 2)
Simplified:
2⋅2⌊log2⌋ − 1
And because the exponentiation compensates the logarithm, this is linear order of magnitude in terms of :
2⋅2⌊log2⌋ − 1 = O(2 − 1) = O()
Intuition
One key here is that the logarithm and exponentiation absorb each other.
To get a feel for it, note how the number of iterations of the outer loop does not change whether is 16, 17, 18, 19, 20, ... or even 31. In all these cases the outer loop executes 5 times, and the inner loop executes 1+2+4+8+16 = 31 times. Compared to when is 16, the number of outer iterations is only increased by one when doubles. The result is that the inner body execution also approximately doubles then... so those two "events" really go hand in hand... linearly.
See this table for different values of :
|
number of inner body executions |
1 |
1 |
2 |
3 |
3 |
3 |
4 |
7 |
5 |
7 |
6 |
7 |
7 |
7 |
8 |
15 |
9 |
15 |
10 |
15 |
11 |
15 |
12 |
15 |
13 |
15 |
14 |
15 |
15 |
15 |