How to fix my numberOfDigits function

I went through some code where the number of digits was determined by casting the numbers into a string, and then using len ().

Function numOfDigits_len(n As Long) As Long numOfDigits_len = Len(Str(n)) - 1 End Function 

Now, although this works, I knew that it would be slow compared to any method that didn't use strings, so I wrote one that uses log ().

 Function numOfDigits_log(n As Long) As Long numOfDigits_log = Int(Log(n) / Log(10)) + 1 End Function 

Reduce the lead time by 1/2, which was great, but there was something strange in the particular case.

  n numOfDigits_log(n) ===== ==================== 999 3 1000 3 1001 4 

It will not handle 1000 correctly. I decided that this was due to floating point and rounding issues.

 Function numOfDigits_loop(ByVal n As Long) As Long Do Until n = 0 n = n \ 10 numOfDigits_loop = numOfDigits_loop + 1 Loop End Function 

I wrote this, which turned out to be ~ 10% slower, since the numbers got more than 10 ^ 6 and seem to become slower large with increasing n. Which is good if I was pragmatic, but I would like to find something more ideal.

Now my question is: is there a way to use the log () method exactly. I could do something like

 Function numOfDigits_log(n As Long) As Long numOfDigits_log = Int(Log(n) / Log(10) + 0.000000001) + 1 End Function 

But it seems very "hacked." Is there a better way that is faster or faster than the log () method? Note. I understand that such optimization is in many cases pointless, but now that I’ve come across this, I would like to “fix” it.

+6
source share
3 answers

I already talked about this before, but I could not find it, so here are the basics:

 int i = ... some number >= 0 ... int n = 1; if (i >= 100000000){i /= 100000000; n += 8;} if (i >= 10000){i /= 10000; n += 4;} if (i >= 100){i /= 100; n += 2;} if (i >= 10){i /= 10; n += 1;} 

This is in C, but you get the idea.

+1
source

The while loop guarantees correctness, i.e. does not use floating point calculations

 int numDigits = 0; while(num != 0) { num /= 10; numDigits++; } 

You can also speed it up using a larger divisor

 int numDigits = 0; if(num >= 100000 || num <= -100000) { int prevNum; while(num != 0) { prevNum = num; num /= 100000; numDigits += 5; } num = prevNum; numDigits -= 5; } while(num != 0) { num /= 10; numDigits++; } 
+1
source

You will like it.

We live in a basic system with 10 numbers! This means that all you have to do is ROUND UP.

the length of a number ALWAYS = ceiling (log n) . So, for example: 7456412 (7-digit number). Log (7456412) = 6.8 ... round up and you have 7. log (9999) = 3.9999. Round up and it's 4.

A special case is that you DO NOT need to round or when you have a power of 10. For example: log (1000) = 3. If you can find when you have a power of 10, add one to the result of the log and you will win!

the way you could make this discovery is something like

 double log10; int clog10; int length; log10 = (Log(n) / Log(10)); // can also use a private static final long hardcoded for Log(10) clog10 = ceiling(log10); if (Int(log10) == clog10) length = clog10 + 1; else length = clog10; 
0
source

Source: https://habr.com/ru/post/947685/


All Articles