The operation can be performed in (fast) constant time on any architecture that has a zero-start or similar instruction (which is the majority of architectures). Here's the C fragment I'm sitting in, calculates the number of digits in the base ten, which is essentially the same task (assumes a gcc-like compiler and a 32-bit int):
unsigned int baseTwoDigits(unsigned int x) { return x ? 32 - __builtin_clz(x) : 0; } unsigned int tenToThe[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, }; unsigned int baseTenDigits(unsigned int x) { unsigned int guess[33] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9 }; unsigned int digits = guess[baseTwoDigits(x)]; return digits + (x >= tenToThe[digits]); }
GCC and clang compile this to ~ 10 instructions on x86. With caution, you can speed up the assembly process.
The key concept is to use the (extremely cheap) base-two logarithm to quickly evaluate the base-ten logarithm; at this point, we need to compare only one force in ten to decide whether we need to correct guesses. This is much more effective than finding several degrees in ten to find the right one.
If the inputs are overwhelmingly biased to single and double digit numbers, linear scanning sometimes happens faster; for all other input distributions, this implementation tends to win quite conveniently.