Count of digits in Integer

Hi,
how can I count how many digits are in Integer?
Do I have to Cstr it and count chars?
Thanks!

Jukka

make a while loop and count how often you make an integer division by 10 until you get zero.

I thought exactly the same as you, but Len(str(Integer)) is probably at least as efficient as the more obvious math functions. Of course you’d also have to check for -ve numbers & remove the “-” if present.

I agree with Wayne

x=len(replace(str(myNum),"-",""))

this short method is 27% faster than the div by 10 method

One Million interations of Div by 10 took 1.140194 seconds on my iMac
the same for the short method took only 0.8934856 seconds… of 27.6% times faster

So… two advantages

  1. its faster
  2. it only ONE line of code

for those who care… here it the test code I used… working on a 10 digit number

  Const pass=1000000
  Dim myNum As Integer=1234567890
  Dim ms As Double
  Dim i As Integer
  Dim z As Integer
  Dim cnt As Integer
  Dim t1 As Double
  Dim t2 As Double
  ms=Microseconds
  For i=1 To pass
    z=mynum
    cnt=0
    Do
      cnt=cnt+1
      z=z/10
      If z=0 Then Exit Do
    Loop
  Next i
//
//
//
  t1=(Microseconds-ms)/1000000
  ms=Microseconds
  For i=1 To pass
    cnt=Len(Replace(Str(mynum),"-",""))
  Next i
  t2=(Microseconds-ms)/1000000
  MsgBox Str(t1/t2)+"A="+Str(t1)+" b+"+Str(t2)

What if you use Abs instead of Replace?

believe it or not it is SLOWER

using ABS took 1.239 vs REPLACE at 0.89

I can believe it. :slight_smile:

What about putting an If to avoid Replace if the number > 0?

I tried with pos/neg numbers and diff could be written off to noise.

If you could test one more idea (since you’re set up for it already):

l = Len( Str( mynum ) ) 
if mynum < 0 then l = l - 1

Dave, I just ran the tests here and using your len(str(mynum)) is faster in the IDE, but significantly slower in a compiled app. In the IDE, I get: 1.075254A=1.444735 b+1.343622, but once compiled, I get: 0.2212502A=0.2842035 b+1.284534. I can cut that down somewhat by using LenB/ReplaceB, but it’s still not nearly as fast as the loop. And if I switch to integer division, it’s no contest: 0.1187273A=0.0792469 b+0.66747.
(that’s using LenB/ReplaceB.) More, if I use multiplication instead of division (keep multiplying a test number until it’s greater than the target), it’s faster still.

Finally, if I switch to an array and If statements, it’s slightly faster than multiplication. Here is the complete code:

  #pragma BackgroundTasks False
  
  Const pass=1000000
  Dim myNum As Integer=1234567890
  Dim ms As Double
  Dim i As Integer
  Dim z, n As Integer
  Dim cnt As Integer
  Dim t1, t2, t3 As Double
  
  ms=Microseconds
  For i=1 To pass
    'z=mynum
    'cnt=0
    'Do
    'cnt=cnt+1
    'z=z\\10
    'If z=0 Then Exit Do
    'Loop
    
    n = mynum
    if n < 0 then n = 0 - n
    z = 10
    cnt = 1
    while z <= n
      cnt = cnt + 1
      z = z * 10
    wend
  Next i
  t1=(Microseconds-ms)/1000000
  
  ms=Microseconds
  For i=1 To pass
    cnt=LenB(ReplaceB(Str(mynum),"-",""))
    'cnt = LenB( str( mynum ) )
    'if mynum < 0 then cnt = cnt - 1
  Next i
  t2=(Microseconds-ms)/1000000
  
  
  ms = Microseconds
  static intChart() as integer
  if intChart.Ubound = -1 then
    #if Target64Bit
      redim intChart( 17 )
    #else
      redim intChart( 9 )
    #endif
    for i = 1 to intChart.Ubound
      intChart( i ) = 10^i
    next
  end if
  
  n = mynum
  if n < 0 then n = 0 - n
  for i = 1 to pass
    for index as integer = intChart.Ubound downto 1
      if n >= intChart( index ) then
        cnt = index + 1
        exit
      end if
    next index
  next i
  t3 = ( Microseconds - ms ) / 1000000
  
  AddToResult Str(t1/t2)+"A="+Str(t1)+" b+"+Str(t2)
  AddToResult str( t3 ) + " (if)"

In a compiled app, I get:

0.0549121A=0.0367037 b+0.6684084
0.0218872 (if)

Well, with Replace and Str allocating new memory for a small string and Len counting UTF8 characters, I would expect that Len alone takes longer than the div loop.
Especially if you use #pragma disableBackgroundTasks for this loop to avoid yielding time.

As long as we’re only talking about 32 bit integers… this is surprisingly fast

  
  ms=Microseconds
  for i=1 to pass
    if myNum<0 then
      n=0-myNum
    Else
      n=myNum
    end if
    Select case true
    case n>=1000000000
      cnt=10
    case n>=100000000
      cnt=9
    case n>=10000000
      cnt=8
    case n>=1000000
      cnt=7
    case n>=100000
      cnt=6
    case n>=10000
      cnt=5
    case n>=1000
      cnt=4
    case n>=100
      cnt=3
    case n>=10
      cnt=2
    else
      cnt=1
    end select
    
  next i
  t4 = (Microseconds -ms) / 1000000

Expanding to encompass 64bit still runs pretty fast! (don’t forget to test a variety of lengths for myNum)

Yes, I tried that, and it was the fastest of all the other methods. I just felt it was too unwieldy, especially at 64 bits.

Instead of doing a loop dividing by ten, you could also get the log10, which should be faster.

Something like this:

Function Digits(i as integer) As integer if i = 0 then return 1 return ceil (log(abs (i) +1) / log(10)) End Function

if you want to also count the “-” in negative values, use this:

Function Digits(i as integer) As integer if i = 0 then return 1 if i < 0 then return ceil (log(abs (i) +1) / log(10)) + 1 else return ceil (log(i +1) / log(10)) end if End Function