Problem 29
Question
This exercise develops an algorithm to compute \(\lfloor\sqrt{n}\rfloor\) for a given positive integer \(n\). Consider the following algorithm: \(k \leftarrow\lfloor(\operatorname{len}(n)-1) / 2\rfloor, m \leftarrow 2^{k}\) for \(i \leftarrow k-1\) down to 0 do if \(\left(m+2^{i}\right)^{2} \leq n\) then \(m \leftarrow m+2^{i}\) output \(m\) (a) Show that this algorithm correctly computes \(\lfloor\sqrt{n}\rfloor\). (b) In a straightforward implementation of this algorithm, each loop iteration takes time \(O\left(\operatorname{len}(n)^{2}\right),\) yielding a total running time of \(O\left(\operatorname{len}(n)^{3}\right)\). Give a more careful implementation, so that each loop iteration takes time \(O(\operatorname{len}(n)),\) yielding a total running time is \(O\left(\operatorname{len}(n)^{2}\right) .\)
Step-by-Step Solution
VerifiedKey Concepts
Integer Square Root
To compute the integer square root of a number efficiently, algorithms leverage properties of powers of two. The algorithm in question begins by estimating the potential size of the integer square root through computation involving the length of the number \( n \) and powers of 2. It iteratively refines this estimate by testing whether adding additional powers of 2 keeps the square of the result within bounds. As a result, the value \( m \) that the algorithm computes will be the integer that satisfies \( m^2 \leq n < (m+1)^2 \). This way, it ensures the accurate computation of \( \lfloor\sqrt{n}\rfloor \).
Algorithm Optimization
Initially, the algorithm recalculates squares repeatedly which results in substantial computational overhead. Instead, by storing intermediate results such as \( m^2 \), the operation \((m+2^i)^2 \leq n\) can be simplified. This simplification involves breaking it down into already known terms - the previously computed \( m^2 \) and additional components using the identity:
- \( (m+2^i)^2 = m^2 + 2^{i+1}m + 2^{2i} \).
Time Complexity Analysis
In the original implementation, the inner workings of each loop iteration led to a time complexity of \( O(\operatorname{len}(n)^{3}) \). This is because it spent \( O(\operatorname{len}(n)^{2}) \) time reevaluating squares. However, upon optimizing by storing \( m^2 \) and utilizing the relationship for calculating squares incrementally, time per iteration is reduced to \( O(\operatorname{len}(n)) \).
The total time complexity then becomes \( O(\operatorname{len}(n)^{2}) \), as there are \( O(\operatorname{len}(n)) \) iterations. This streamlined complexity makes the algorithm scalable and more efficient, particularly for larger numbers, which is invaluable in applications requiring rapid computations over vast datasets.