Hi,
how can I count how many digits are in Integer?
Do I have to Cstr it and count chars?
Thanks!
Jukka
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
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.
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