Increment an integer without SET

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

Increment an integer without SET

#1 Post by einstein1969 » 17 Oct 2013 04:43

hi to all,

Does anyone know how to increment a variable that contains the representation of an integer?

I would suffice the increase of 1 or a few units

I would avoid the use of the SET (or the SET / A) and if possible use only one or two expansions (or if there is a chance even three). So that is faster than the use of the "SET".

I need to numbers ranging from 0 to 8191 (theoretical max for a environment variable for DOS BATCH)

Thanks

Einstein1969

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Increment an integer without SET

#2 Post by jeb » 17 Oct 2013 06:06

I can't see the sense of avoiding set /a :?:

What is wrong with

Code: Select all

set /a myCounter=0
for /F %%L in (text.txt) DO (
  set /a myCounter+=1
)

ShadowThief
Expert
Posts: 1166
Joined: 06 Sep 2013 21:28
Location: Virginia, United States

Re: Increment an integer without SET

#3 Post by ShadowThief » 17 Oct 2013 06:20

I'd be really curious to see how somebody could change the value of a variable without using SET.

Closest thing I can think would be

Code: Select all

for /L %%A in (0,1,8191) do (
    rem whatever you're doing with %%A
)

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

Re: Increment an integer without SET

#4 Post by einstein1969 » 17 Oct 2013 08:28

Ok. I have formuled the question wrong! You are right!

I use this code for change the content of string:

one_char_change:

Code: Select all

setlocal EnableDelayedExpansion

set s=0123456789
set Pos=4
set newvalue=#

set /a Pos2=Pos+1
set s=!s:~0,%Pos%!!newvalue!!s:~%Pos2%!

echo !s!

rem OR

set s=0123456789
set Pos=4
set newvalue=#

set last=!s:~%Pos%!
set s=!s:~0,%Pos%!!newvalue!!last:~1!

echo !s!


It is possibile cut the "set /a Pos2=Pos+1" or "set last=!s:~%Pos%!" and using one SET?

Einstein1969

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

Re: Increment an integer without SET

#5 Post by einstein1969 » 17 Oct 2013 08:34

jeb wrote:I can't see the sense of avoiding set /a :?:


For performance reason (if we can do it)

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

Re: Increment an integer without SET

#6 Post by foxidrive » 17 Oct 2013 08:43

einstein1969 wrote:
jeb wrote:I can't see the sense of avoiding set /a :?:


For performance reason (if we can do it)


If you are looking for performance then why are you using batch?
Even an interpreted basic program will blow batch out of the water for speed.

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

Re: Increment an integer without SET

#7 Post by einstein1969 » 17 Oct 2013 09:08

foxidrive wrote:
einstein1969 wrote:
jeb wrote:I can't see the sense of avoiding set /a :?:


For performance reason (if we can do it)


If you are looking for performance then why are you using batch?
Even an interpreted basic program will blow batch out of the water for speed.


you are right!
I could certainly do the same thing in assembler or any other language or script interpreter etc.

But I'm delving into the batch dos.

Einstein1969

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

Re: Increment an integer without SET

#8 Post by aGerman » 17 Oct 2013 13:28

SET is a CMD - internal command. That means it's as fast as a command can be. No idea why you are thinking it would cause a bad performance in your batch code. If you want to improve the peformance of a batch code the try to avoid external commands (at least try to avoid calling them several times for the same reason).

That code will separate the commands that are listed in HELP:

Code: Select all

@echo off &setlocal

set /a int=0, ext=0
for /f %%i in ('help^|findstr /rbc:"[A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ]"') do (
  for /f "tokens=1,2 delims=?" %%j in ("%%i.exe?%%i.com") do (
    if "%%~$PATH:j%%~$PATH:k"=="" (
      call :out %%i
    ) else (
      set /a ext+=1
      echo %%i "%%~$PATH:j%%~$PATH:k"
    )
  )
)

echo(
echo internal %int%
echo external %ext%
pause>nul
goto :eof

:out
set /a int+=1
set "line=%1                                                  "
echo %line:~,50% - internal
goto :eof

Regards
aGerman

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

Re: Increment an integer without SET

#9 Post by einstein1969 » 17 Oct 2013 15:21

Thank you for the wise suggestion, but I'm using at the moment few external commands. I'll probably have to revise the logic to break down the problem of declining performance.

This script is phenomenal! :shock: It will take me a double cup of coffee to figure out how do you generate the list. :roll:

Anyway back to the problem of performance. I saw that SET is fast but sometimes it is slower than an expansion. So I thought that populate a variable upstream then use it would be good for performance. My goal is both qualitative (functional) and performance.

Einstein1969

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

Re: Increment an integer without SET

#10 Post by aGerman » 17 Oct 2013 16:16

I'm using at the moment few external commands

You can't avoid it. What I actually meant is that you could use COPY instead of XCOPY if you simply have to copy a file. Or that you could apply FINDSTR to a file / a set of files instead of applying it to each line / each file separately.
The reason why it decreases the performance enormously is that Windows needs some time to load the process. Depending on RAM, number of CPUs, clocking, current CPU usage etc. it wastes approx. 200ms each time you call an external command.

It will take me a double cup of coffee to figure out how do you generate the list.

Actually it's very simple. I process the list of commands that the HELP command displays. I append .exe and .com to the commands and use the ~$path: modifier of FOR variables to check if such a file can be found in the PATH environment.

Regards
aGerman

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

Re: Increment an integer without SET

#11 Post by einstein1969 » 17 Oct 2013 18:48

aGerman wrote:
I'm using at the moment few external commands

You can't avoid it. What I actually meant is that you could use COPY instead of XCOPY if you simply have to copy a file. Or that you could apply FINDSTR to a file / a set of files instead of applying it to each line / each file separately.
The reason why it decreases the performance enormously is that Windows needs some time to load the process. Depending on RAM, number of CPUs, clocking, current CPU usage etc. it wastes approx. 200ms each time you call an external command.

It will take me a double cup of coffee to figure out how do you generate the list.

Actually it's very simple. I process the list of commands that the HELP command displays. I append .exe and .com to the commands and use the ~$path: modifier of FOR variables to check if such a file can be found in the PATH environment.

Regards
aGerman


Thanks for explain aGerman.

Yes, I can't avoid. But depend of nature of application. There are application that use 200ms for call external program and 20000ms of internal command. And if i reduce of 40% than i'm happy.

Meanwhile i have find a way.... difficult to follow

for value from 0 to 8 (I dread to think how to get to 8192)

result:

Code: Select all

Without SET /A
#123456789
##23456789
###3456789
####456789
#####56789
######6789
#######789
########89
#########9

With SET /A
#123456789
##23456789
###3456789
####456789
#####56789
######6789
#######789
########89
#########9


Code: Select all

@echo off & setlocal EnableDelayedExpansion

set newvalue=#

set pos2=1234567890

set s=0123456789

echo Without SET /A

For /L %%# in (0,1,8) do (
   rem set /a Pos2=Pos+1
   for %%A in ("!Pos2:~%%#,1!") do set s=!s:~0,%%#!!newvalue!!s:~%%~A!
   echo !s!
)

set s=0123456789
echo(
echo With SET /A

For /L %%# in (0,1,8) do (
   set /a Pos2=%%#+1
   for %%A in (!Pos2!) do set s=!s:~0,%%#!!newvalue!!s:~%%A!  <---can optimize this?
   echo !s!
)


Timing:

Code: Select all

   Environ       Grow   Change a string with:
      Size     Environ   SET/A +1    EXP_EQ.   GAIN
   ----------------------------------------------------
      4907       0.00       2.65       2.17     19%
     15451       0.01       3.98       2.89     28%
     36052       0.02       7.22       4.66     36%
     77252       0.06      15.68       9.74     38%
    159705       0.27      33.85      19.14     44%


How do I make the rest of the numbers?

Einstein1969

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Increment an integer without SET

#12 Post by Aacini » 21 Oct 2013 19:24

Perhaps is this what you want?

Code: Select all

@echo off & setlocal EnableDelayedExpansion

for /L %%a in (0,1,9) do (
   set inc[!last!]=%%a
   set last=%%a
)

set newvalue=#

set s=0123456789

echo REALLY Without SET /A
For /L %%# in (0,1,8) do (
   for %%A in (!inc[%%#]!) do set s=!s:~0,%%#!!newvalue!!s:~%%A!
   echo !s!
)

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Increment an integer without SET

#13 Post by carlos » 21 Oct 2013 22:27

More speedy:

Code: Select all

Echo #123456789
Echo ##23456789
Echo ###3456789
Echo ####456789
Echo #####56789
Echo ######6789
Echo #######789
Echo ########89
Echo #########9

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

Re: Increment an integer without SET

#14 Post by einstein1969 » 22 Oct 2013 05:43

@Aacini

Aacini wrote:Perhaps is this what you want?

Code: Select all

@echo off & setlocal EnableDelayedExpansion

for /L %%a in (0,1,9) do (
   set inc[!last!]=%%a
   set last=%%a
)

set newvalue=#

set s=0123456789

echo REALLY Without SET /A
For /L %%# in (0,1,8) do (
   for %%A in (!inc[%%#]!) do set s=!s:~0,%%#!!newvalue!!s:~%%A!
   echo !s!
)


Thanks Aacini , this work but I had already considered the use of "classic" vector . But for performance issues I'm trying to use as few variables as possible. Without going to the extreme dictated by carlos: D I found a solution by using a mechanism such as the "map and lookup" described on the site even though it is currently limited to much lower values ​​than 8192 which was my original goal.

However, for the moment, your solution is the best because overcomes the limitation of 8192

ingenious use of the "last" in your code 8)

my last code:

Code: Select all

@echo off & setlocal EnableDelayedExpansion

set newvalue=#

rem create like this ....20-20#21-21#22-22#23-23#24-24#25-25#26-26#27-27#28-28#29-....

set newpos2=
For /L %%# in (0,1,98) do (
   
   set /a ns=%%#+1
           set ns=0!ns!
   set n=0%%#
   set n=!n:~-2!#!ns:~-2!-
   set newpos2=!newpos2!!n!
       
)

rem echo !newpos2!

rem test

set s=0123456789abcdefghijklhmenopqrstuvwxyz

set pos=19
for /f "delims=-" %%t in ("!newpos2:*%pos%#=!") do set s=!s:~0,%pos%!!newvalue!!s:~%%t!
echo !s!



@carlos

nice :D

I'm seriously thinking that it is the best solution at the time. Just prepare before everything and then use it at the appropriate time. Brilliant!

But to get the result must always pass for processing ...

Use the best environment I think is one of my goals or even a presentiment that it is a path with no way out ...

Einstein1969

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Increment an integer without SET

#15 Post by carlos » 22 Oct 2013 10:43

I think that the task can coded in many ways, But the best principle for programming is "Programming only that you need". The really task is print the number of sharp.
In this case, we have a union in that in row 1 we print 1 sharp, in row 2 we print 2 sharps.
In all the task we need index variables, but because you need not use a environment variable, we choose a for /l variable.
And also we have other option, use a counter for print 1 sharp, for example if we need print 3 asterisk do for /l %%# in (1,1,3) do print # or have a hardcoded variable for print %var:~1,3%

Then there are variants of programming.

This is a option:

Code: Select all

@Echo Off
SetLocal EnableDelayedExpansion

Set num=_123456789
Set rep=_#########
For /L %%R in (1,1,9) Do Echo !rep:~1,%%R!!num:~%%R!

Pause


and other variant:

Code: Select all

@Echo Off
SetLocal EnableDelayedExpansion

Set num=123456789
Set rep=#########
For /L %%R in (0,1,8) Do Echo #!rep:~0,%%R!!num:~%%R!

Pause

Post Reply