I have timed methods with the following variations in C ++ for a value of type size_t (nesting improves performance but does not change the relative order).
Try 1: Multiply until it finds the number.
size_t try1( size_t a ) { size_t scalar = 1ul; while( scalar * 10 < a ) scalar *= 10; return scalar; }
Try 2: Multiway if (can also be programmed using the lookup table).
size_t try2( size_t a ) { return ( a < 10ul ? 1ul : ( a < 100ul ? 10ul : ( a < 1000ul ? 100ul : ( a < 10000ul ? 1000ul : ( a < 100000ul ? 10000ul : ( a < 1000000ul ? 100000ul : ( a < 10000000ul ? 1000000ul : ( a < 100000000ul ? 10000000ul : ( a < 1000000000ul ? 100000000ul : ( a < 10000000000ul ? 1000000000ul : ( a < 100000000000ul ? 10000000000ul : ( a < 1000000000000ul ? 100000000000ul : ( a < 10000000000000ul ? 1000000000000ul : ( a < 100000000000000ul ? 10000000000000ul : ( a < 1000000000000000ul ? 100000000000000ul : ( a < 10000000000000000ul ? 1000000000000000ul : ( a < 100000000000000000ul ? 10000000000000000ul : ( a < 1000000000000000000ul ? 100000000000000000ul : ( a < 10000000000000000000ul ? 1000000000000000000ul : 10000000000000000000ul ))))))))))))))))))); }
Try 3: Changed from findPow10 @Saaed Amiri, which uses a square to quickly find very large capacities than Try 1.
size_t try3( size_t a ) { if (a == 0) return 0; size_t i, j = 1; size_t prev = 1; while( j != 100 ) { i = prev; j = 10; while (i <= a) { prev = i; i *= j; j *= j; } } return prev; }
Try 4: a lookup table indexed using the leading zero count command according to @Ira Baxter.
static const std::array<size_t,64> ltable2{ 1ul, 1ul, 1ul, 1ul, 1ul, 10ul, 10ul, 10ul, 100ul, 100ul, 100ul, 1000ul, 1000ul, 1000ul, 1000ul, 10000ul, 10000ul, 10000ul, 100000ul, 100000ul, 100000ul, 1000000ul, 1000000ul, 1000000ul, 1000000ul, 10000000ul, 10000000ul, 10000000ul, 100000000ul, 100000000ul, 100000000ul, 1000000000ul, 1000000000ul, 1000000000ul, 1000000000ul, 10000000000ul, 10000000000ul, 10000000000ul, 100000000000ul, 100000000000ul, 100000000000ul, 1000000000000ul, 1000000000000ul, 1000000000000ul, 1000000000000ul, 10000000000000ul, 10000000000000ul, 10000000000000ul, 100000000000000ul, 100000000000000ul, 100000000000000ul, 1000000000000000ul, 1000000000000000ul, 1000000000000000ul, 1000000000000000ul, 10000000000000000ul, 10000000000000000ul, 10000000000000000ul, 100000000000000000ul, 100000000000000000ul, 100000000000000000ul, 100000000000000000ul, 1000000000000000000ul, 1000000000000000000ul }; size_t try4( size_t a ) { if( a == 0 ) return 0; size_t scalar = ltable2[ 64 - __builtin_clzl(a) ]; return (scalar * 10 > a ? scalar : scalar * 10 ); }
Dates: (gcc 4.8)
for( size_t i = 0; i != 1000000000; ++i) try1(i) 6.6 for( size_t i = 0; i != 1000000000; ++i) try2(i) 0.3 for( size_t i = 0; i != 1000000000; ++i) try3(i) 6.5 for( size_t i = 0; i != 1000000000; ++i) try4(i) 0.3 for( size_t i = 0; i != 1000000000; ++i) pow(10,size_t(log10((double)i))) 98.1
Lookup / multiway-if is superior to everything in C ++, but requires that we know that integers are of finite size. try3 slower than try1 in this test for smaller values ββof the final value of the loop; for larger numbers of try3 , the beat of try1 . In python, everything is difficult to do because integers are unlimited, so I would combine try2 with try3 to quickly process numbers to a fixed limit and then process, possibly very large numbers.
In python, I think searching using list comprehension is probably faster than multi-page. if.
# where we previously define lookuptable = ( 1, 10, 100, ..... ) scalar = [i for i in lookuptable if i < a][-1]