In the code below, all of the test cases are commented out. Besides that, each case is given a line number and placed in the order of fastest to slowest, as benchmarked by me. The times I got are placed in comments after each case. The non-approximate times are average times over 5 runs of that case.
I would encourage you to do your own testing of each case to confirm my results. Per case times on different PCs are meaningless. The only significance is in comparing each case to the others.
To test each case, uncomment just that line and run the program. The time in milliseconds will eventually appear in the main window. To maintain consistancy, please try to keep background applications to a minimum, especially media players and the like that may place varying loads on the CPU.
I conclude that the obvious method (case #8) is not the fastest way to compute the number of digits in a number. As I've stated before, strings cost a lot of CPU cycles. Additionally, the prettiest methods, the function calls (#9 and #10), turn out to be far worse than any inline code do to the overhead of a function call. The fastest method (#1) is an eye-opener because it is counter-intuitive. It shows that a run-time computation can be, on average, faster than a variable holding that same value, computed even before the time started. Despite this anomaly, the precomputed value of log(10) in many of the leaders shows that precomputing constants is generally the thing to try when you are attempting to optimize code for speed. Still, given the closeness in the times between #1 and #2, others' tests might flip these twp.
Another conclusion I draw from these tests is that global variables are slower than local variables, even in the main program block. This is another odd situation with a non-intuitive result. I have no idea at this moment why the scope of a variable should have such a drastic effect on the execution speed.
Please note that most of the given cases are not robust and require an input that is a counting number--zero and negative numbers will cause the program to crash in the absense of an ON ERROR. Cases #7 and #10 will accept any integer value. But unlike #8, which will count the minus sign in the number, the previously mentioned cases do not. This was done to keep this clean and clear.
I welcome your comments and would like very much to know if your results are different for mine.
Code: |
n = 123456789
Global g.LogOf10, g.Big1 LogOf10 = Log(10) : g.LogOf10 = LogOf10 Big1 = 1 + 1e-300 : g.Big1 = Big1 Epsilon = 1e-300 t = Time$("ms") For i = 1 To 1000000 ' 1 c = Int(Log(n) / LogOf10 + 1 + 1e-300) ' 9.328s ' 2 c = Int(Log(n) / LogOf10 + Big1) ' 9.4032s ' 3 c = Int(Log(n) / Log(10) + Big1) ' 11.6186s ' 4 c = Int(Log(n) / Log(10) + 1 + 1e-300) ' 11.6846s ' 5 c = Int(Log(n) / LogOf10 + 1 + Epsilon) ' 11.756s ' 6 c = Int(Log(n) / g.LogOf10 + g.Big1) ' ~14.5s ' 7 If n Then c = Int(Log(Abs(n)) / LogOf10 + 1 + 1e-300) Else c = 1 ' ~15.5s ' 8 c = Len(Str$(n)) ' ~16s ' 9 c = CountingDigits(n) ' ~51s '10 c = NumberOfDigits(n) ' ~60s Next Print Time$("ms") - t 'Print c End Function CountingDigits ( Num ) CountingDigits = Int(Log(Num) / Log(10) + 1 + 1e-300) End Function Function NumberOfDigits ( Num ) If Num Then NumberOfDigits = Int(Log(Abs(Num)) / Log(10) + 1 + 1e-300) Else NumberOfDigits = 1 End Function |