In the example you give, b equals 3. The number of bits in the binary representation of 3 is $\ell = 2$.

In the abstract iterated squaring algorithm, to compute $a^3$, we first compute $a^2$ (which takes one multiplication), and then compute $a^3 = a \cdot a^2$, which takes another multiplication. So overall we got here $2(\ell -1) = 2$ multiplications, in line with the claim given in class.

Let us now examine the specific code given in class (note that the code is somewhat mysterious. A proof of its correctness was partially presented in class, and is fully laid out in the slides. It is **highly** recommended to read and understand it).

def power(a,b):
""" computes a**b using iterated squaring """
result=1
while b>0:
if b % 2 == 1:
result = result*a
a=a**2
b = b//2
return result

The loop is executed twice. Once where b equals 3, and the second time with b equals 1. Indeed, there are nominally 2 multiplications in each iteration (since b is odd in both), so overall the number of multiplications is

$2\ell = 4$ and not

$2(\ell -1) = 2$. Note that the first multiplication is multiplying by 1. We could modify the code to test if this is the case, and "save" one multiplication. Likewise, the last multiplication computes

$a^2 \cdot a^2 = a^4$, which is wasteful. This multiplication, too, could be eliminated by an appropriate condition.

To conclude, the abstract iterated squaring algorithm indeed employs up to $2(\ell -1)$ multiplications. The actual code mimics it, but **not exactly**, and could perform up to $2\ell$ multiplications. In practice it is way better because it does not store all powers $a, a^2, a^4,\ldots,a^{2^{\ell - 1}}$, which the abstract algorithm needs.

Finally, I would like to commend Ms. anonymous guest for taking the time to observe this and post it in the forum.