Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Sort of trivial code challenge - may be interesting to you anyway Date: Wed, 11 Mar 2026 07:57:52 -0700 Organization: A noiseless patient Spider Lines: 86 Message-ID: <86zf4e8lcf.fsf@linuxsc.com> References: <10n80sc$3soe4$1@dont-email.me> <86v7feei2e.fsf@linuxsc.com> <10o53k6$1i0ef$2@dont-email.me> <86ms0peby6.fsf@linuxsc.com> <10ockdh$3qpk6$1@dont-email.me> <10ocrjn$3qpk6$2@dont-email.me> <10od30j$79v9$1@dont-email.me> <20260307220446.000077d9@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Wed, 11 Mar 2026 14:57:59 +0000 (UTC) Injection-Info: dont-email.me; posting-host="5f44bcdbc02769ce6998caa4a4cb2206"; logging-data="1172321"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18Q5P7+nsyJj6mS9nogOjs/4gxeREdr6qQ=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:VHTQscShBYQaQEUflcvbSSWZ9Ow= sha1:L80dl6mwnQM8sTGzjYUtEfOrNeA= Xref: csiph.com comp.lang.c:396904 Michael S writes: [concerning implementing integer square root] > Here is O(log(N)) variant [...] > > unsigned usqrt(unsigned x) > { > if (x < 2) > return x; > unsigned y = x/2, r; > while ((r = x / y) < y) > y = (r + y) / 2; > return y; > } Right, O(log(N)). The initial guess is kind of out in left field so it takes a while to get into a good zone of convergence. > And here is variation that is a little less simple, but not > complicated and faster than one before, because it does fewer > divisions. The number of divisions that can't be implemented as > shift is at most ceil(sqrt(ceil(log2(ceil(sqrt(val))) > > unsigned usqrt(unsigned x) > { > if (x < 2) > return x; > unsigned y = 8, xx = x; > while (xx > 63) { > xx /= 64; > y *= 8; > } > unsigned r; > while ((r = x / y) < y) > y = (r + y) / 2; > return y; > } Here I think your analysis is a little off. Newton's Method has quadratic convergence, given an appropriate initial guess. That means the second while loop is O(log(# bits)), or O(log(log(N))). The initial loop, to find a good initial guess, can also be made to be O(log(log(N))); exercise for the reader. The foregoing assumes the usual C operators are O(1), which of course isn't right as the width of the type involved gets larger, but that assumption is typically made in this kind of analysis. (Note: since the width of unsigned int is fixed, technically the performance of these algorithms is all O(1). But usually that condition of constant width is ignored in this sort of discussion.) > And here is less simple but still obvious implementation that does > no divisions at all. No multiplications as well. > > unsigned usqrt(unsigned x) > { > if (x < 2) > return x; > unsigned xx = x; > int e = 0; > while (xx > 63) { > xx /= 64; > e += 3; > } > while (xx > 3) { > xx /= 4; > e += 1; > } > unsigned y = 1u << e; > x -= y << e; > for (e = e - 1; e >= 0; --e) { > unsigned d = y*2 + (1u << e); > if (d <= (x >> e)) { > x -= d << e; > y += 1u << e; > } > } > return y; > } Here the behavior is linear in the number of bits, or O(log(N)). At some point (but not for 32-bit integers) the division method wins out.