Fastest way to get number of decimal digit

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Fastest way to get number of decimal digit

#1 Post by einstein1969 » 23 Mar 2014 09:09

Hi to all,

I need to count the number of char in a string. This is the lenght of the string.

But the string that i use is composed from only decimal digit (0123456789) and the lenght max is 9.

examples of numbers:

Code: Select all

set N1=123456789
set N2=5604
set N3=0


what is the fastest way?

einstein1969

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Fastest way to get number of decimal digit

#2 Post by foxidrive » 23 Mar 2014 09:54

Test these:


Code: Select all

@echo off
set pre=.abc
for /f "tokens=1* delims=:" %%a in (
   '^(for %%i in ^("%pre%" .^) do @echo %%i^) ^| findstr /o .^| findstr /v /b 0') do set /a var=%%~a-5



Code: Select all

@echo off

:: Space char. substitution below (I used a period) was necessary as when %* or %VAR% is expanded by
:: the for-in-do below, it concatenated any number of sequential spaces to 1 space destroying an
:: accurate count
set "VAR=%*"
set "var=%var: =.%"
for /f "delims=[] tokens=1" %%l in (
 'cmd /u /c echo/%VAR%^|find /v /n ""') do set /a CNT=%%l-3

if %CNT% EQU -3 set CNT=0
echo %CNT%
pause


Code: Select all

@echo off
set "string=aaa bbb ccc"
call :a abc string
echo %abc%
pause
goto :EOF
:a
(   
    setlocal EnableDelayedExpansion
    set "s=!%~2!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" (
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
(
    endlocal
    set "%~1=%len%"
    exit /b
)


Code: Select all

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for %%a in (*.txt) do (
set "name=%%~na"
call :strlen name len
rem if !len! GTR 7 del "%%a"
)
pause
goto :eof



:strLen string len -- returns the length of a string
::                 -- string [in]  - variable name containing the string being measured for length
::                 -- len    [out] - variable to be used to return the string length
:: Many thanks to 'sowgtsoi', but also 'jeb' and 'amel27' dostips forum users helped making this short and efficient
:$created 20081122 :$changed 20101116 :$categories StringOperation
:$source http://www.dostips.com
(   SETLOCAL ENABLEDELAYEDEXPANSION
    set "str=A!%~1!"&rem keep the A up front to ensure we get the length and not the upper bound
                     rem it also avoids trouble in case of empty string
    set "len=0"
    for /L %%A in (12,-1,0) do (
        set /a "len|=1<<%%A"
        for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
    )
)
( ENDLOCAL & REM RETURN VALUES
    IF "%~2" NEQ "" SET /a %~2=%len%
)
EXIT /b

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Fastest way to get number of decimal digit

#3 Post by aGerman » 23 Mar 2014 10:43

I think foxis 3rd approach could be easily improved to meet your expectations.

Code: Select all

@echo off
set "num=987654321"

setlocal EnableDelayedExpansion
set /a "n=1%num%, len=0"
for %%P in (8 4 2 1) do (
  if "!n:~%%P,1!" NEQ "" (
    set /a "len+=%%P"
    set "n=!n:~%%P!"
  )
)
endlocal &set "len=%len%"

echo %len%
pause

Regards
aGerman

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#4 Post by einstein1969 » 23 Mar 2014 12:34

@foxidrive
thanks! you are very exhaustive. :shock: I have tested and the fastest is 3rd approach as said aGerman

@aGerman
thanks, the for %%P in (8 4 2 1) do .. is more faster. :) I have broken down and this is the result:

Code: Select all

@echo off
set "num=987654321"

setlocal EnableDelayedExpansion
set /a "n=1!num!, len=0"

if "!n:~8,1!" NEQ "" set /a "len=8, n/=100000000"
if "!n:~4,1!" NEQ "" set /a "len+=4, n/=10000"
if "!n:~2,1!" NEQ "" set /a "len+=2, n/=100"
if "!n!" geq "0" set /a "len+=1"

endlocal &set "len=%len%"

echo %len%


but i thinks that is possible to optimize yet. :roll:

EDIT: this approch do not WORK! :twisted:

einstein1969

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fastest way to get number of decimal digit

#5 Post by penpen » 23 Mar 2014 13:13

How about this:

Code: Select all

@echo off
setlocal enableDelayedExpansion
set "$numLength=set "length=0123456789^^^!num^^^!"&set "length=^^^!length:~-10,1^^^!""

set "num=1234567"
%$numLength%
echo(length=%length%

endlocal

penpen

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Fastest way to get number of decimal digit

#6 Post by aGerman » 23 Mar 2014 13:24

@einstein1969
almost right except of the last if statement. You don't need the delayed expansion btw.

Code: Select all

set /a "n=1%num%, len=0"
if "%n:~8,1%" NEQ "" set /a "len=8, n/=100000000"
if "%n:~4,1%" NEQ "" set /a "len+=4, n/=10000"
if "%n:~2,1%" NEQ "" set /a "len+=2, n/=100"
if "%n:~1,1%" NEQ "" set /a "len+=1"


@penpen
very clever :D
Just two lines of code without macro and without delayed expansion. Unbeatable.

Code: Select all

set "len=0123456789%num%"
set "len=%len:~-10,1%"


Regards
aGerman

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#7 Post by einstein1969 » 23 Mar 2014 13:59

I agree! Unbeatable. :shock: :shock:

thanks penpen. :D



einstein1969

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#8 Post by einstein1969 » 23 Mar 2014 15:03

The code was necessary for this but I found another solution.

But I think I will be useful for the other operation. It is possible to check if the lenght of "ops" is less than 19?

You see some optimization to do for this code?

This is fast(use only one SET) add of two natural of max 18 digit (useful also for real fixed point operation)

Code: Select all

@echo off & setlocal EnableDelayedExpansion

set op1=292942778123198
set op2=294822282920383

for /f "tokens=1* delims=0 " %%a in ("A0!op1:~-9!") do for /f "tokens=1* delims=0 " %%c in ("A0!op2:~-9!") do for /f "tokens=1-2" %%h in ("!op1:~0,-9! !op2:~0,-9! 0 0") do (
  set /a "t1=((%%b+(%%d+0)) %% 1000000000)+1000000000, t2=((%%b+(%%d+0)) / 1000000000+(%%h+0)+(%%i+0))"
  for /f "tokens=1* delims=0 " %%e in ("A0!t2!!t1:~-9!") do if "%%f" == "" (echo Tot=0) else echo Tot:%%f
)

Res:

Code: Select all

Tot:587765061043581


einstein1969

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Fastest way to get number of decimal digit

#9 Post by aGerman » 23 Mar 2014 15:40

It is possible to check if the lenght of "ops" is less than 19?

You could use the same technique.

Code: Select all

set "check=x%op1%"
set "check=%check:~-19,1%"
echo %check%

check will only be "x" if the length is less than 19.

Regards
aGerman

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#10 Post by einstein1969 » 23 Mar 2014 16:20

thanks aGerman! It work! 8)

einstein1969

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fastest way to get number of decimal digit

#11 Post by penpen » 23 Mar 2014 17:09

You could avoid all for loops on "op1+op2" (unoptimized);
i hope this is faster (could also be used in a macro to additional speed up, too):

Code: Select all

@echo off
setlocal
set "op1=292942778123198"
set "op2=294822282920383"

set "a=000000000%op1:~-9%"
set "c=000000000%op2:~-9%"
set /A "t2=((ac=(1%a:~-9%-1000000000)+(1%c:~-9%-1000000000))/1000000000)+(%op1:~0,-9%+0)+(%op2:~0,-9%+0)"
if "%t2%" == "0" (
   set "t2="
   set "t1=%ac%"
) else (
   set "t1=000000000%ac%"
)
set "f=%t2%%t1:~-9%"

echo Tot: %f%

endlocal
goto :eof

penpen

Edit: Corrected a bug on trailing 0's.
Edit2: Replaced the missing lines of the code, too; should work now... .
Last edited by penpen on 25 Mar 2014 11:04, edited 1 time in total.

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#12 Post by einstein1969 » 24 Mar 2014 11:21

Hi penpen,

you have missed some.... what is %ac%?

i like see other vision of same problem. It expand and make flexible memory. Thanks!!!

For the macro i like this approch:

einstein1969

Compo
Posts: 600
Joined: 21 Mar 2014 08:50

Re: Fastest way to get number of decimal digit

#13 Post by Compo » 24 Mar 2014 15:53

I don't really understand why speed of execution for an initial input parameter of up to nine digits is so important so here's my basic solution regardless of speed:

Code: Select all

@Echo Off&SetLocal EnableDelayedExpansion
Set "_=%*"&Set "_n=0"
For %%a In (0 1 2 3 4 5 6 7 8 9) Do Set _=!_:%%a=%%a !
For %%a In (%_%) Do Set/a _n+=1
Echo(%_n% digits&Ping -n 6 127.0.0.1 1>Nul
just run it with the digits as an input parameter e.g.
X:\ScriptDir>runbatch.cmd 683673295321065
15 digits

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Fastest way to get number of decimal digit

#14 Post by einstein1969 » 25 Mar 2014 09:18

Compo wrote:I don't really understand why speed of execution for an initial input parameter of up to nine digits is so important so here's my basic solution regardless of speed:

Code: Select all

@Echo Off&SetLocal EnableDelayedExpansion
Set "_=%*"&Set "_n=0"
For %%a In (0 1 2 3 4 5 6 7 8 9) Do Set _=!_:%%a=%%a !
For %%a In (%_%) Do Set/a _n+=1
Echo(%_n% digits&Ping -n 6 127.0.0.1 1>Nul
just run it with the digits as an input parameter e.g.
X:\ScriptDir>runbatch.cmd 683673295321065
15 digits


Thanks Compo for your apport.

Reguard the speed of execution of initial imput parameter, you are right if the rest of the code is expensive/wasteful. In such a case would be negligible.

einstein1969

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fastest way to get number of decimal digit

#15 Post by penpen » 25 Mar 2014 11:07

Sorry, last time i have replaced only the second half of the code although i've rewritten more :oops: .
I've changed the above code, so it should work now (i hope).
To speed up even more, you could make a macro of it; also you may use lesser variables.

penpen

Post Reply