Definition and use of arithmetic "functions" in Batch files

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
penpen
Expert
Posts: 1919
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Definition and use of arithmetic "functions" in Batch fi

#16 Post by penpen » 01 Nov 2015 20:28

No, the batch operator is defined on variable content and substitute strings with (other) strings.
The [] operator is defined on common terms to substitutes a term for a variable within another term, and therefore doesn't substitute functions or operators (or...) even if their labels share the same string:
- "%str:x=y%" equals "(y(y) y y(y))" (set "str=(x(x) x x(x))")
- "(x(x) x x(x))[x=y]" equals "(x(y) x x(y))"

But if names are unique and not contained in each other, then the batch operator could be used to simulate the [] operator (if you meant that).


penpen

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

Re: Definition and use of arithmetic "functions" in Batch fi

#17 Post by Aacini » 01 Nov 2015 21:40

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "str=(x(x) x x(x))"

echo First:  "%str:x=y%"

echo Second: "%str:(x)=(y)%"

set "[x=(x)"
set "y]=(y)"
echo Third:  "!str:%[x%=%y]%!"

Although this "substitution operator" is interesting indeed, it bears no relation to the standard way that most programming languages use to define and invoke arithmetic functions!

penpen wrote:I must admit i never heard of a programming language that "naturally" supports this operator.

Then, why you introduced it in a thread whose purpose is to write something in the way most other programming languages does? :?

Antonio

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

Re: Definition and use of arithmetic "functions" in Batch fi

#18 Post by penpen » 02 Nov 2015 19:22

Aacini wrote:Then, why you introduced it in a thread whose purpose is to write something in the way most other programming languages does? :?

In the opening post you used the words:
Aacini wrote: a method that allows to use arithmetic expressions in Batch files in a way rather similar to arithmetic functions of other programming languages

I posted my suggestion before you have written:
Aacini wrote:the ability to take parameters in a way equivalent to real functions in other programming languages
Aacini wrote:The purpose is to write and execute arithmetic "functions" in a more standard way that may be comprehended by a larger group of people.
So i couldn't take the last two points into account.


I think my suggestion is similar enough; our ways to assign variables don't differ that much, so i posted it, in detail:

Code: Select all

::define: additional "[],"
set "f(x)=(x+2)"
set "g(x)=([], x+3)"

:: invoke: additional "[]="
%f(x):x=1%
%g(x):[]=x=1%
The user doesn't need to know, why "[]" is choosen (special operator) to be replaced (or he could use any other unique string to be replaced); for example he also doesn't know why in most programming languages the parameterlist is at the end of the function header: So this seemed to me less important.

Both versions are invoked in the same way: Replace a string with another (~ variable assignment).
In case of "%f(x):x=1%" the string to be replaced is mentioned within the variable name; but he has to know how to set the variable (and not doing "%f(x=1)%" or "%f(1)%").
In case of %g(x):[]=x=1% he has to know to replace "[]". If that is done for all functions it would be something that is easy to see (similar to setting x in f).

Similar for setting up a function: The user simply must know that he has to use parentheses around the formula (see: "set /A n=2 * %f(x):x=1% * 4"; result 10 versus 24), so the additional "[]," is just another fact to know
(and i initially i had my "consumer view", so i didn't made many thoughts about writing/defining the function, which was an error).


penpen

OperatorGK
Posts: 66
Joined: 13 Jan 2015 06:55

Re: Definition and use of arithmetic "functions" in Batch fi

#19 Post by OperatorGK » 03 Nov 2015 02:08

penpen wrote:
Aacini wrote:Then, why you introduced it in a thread whose purpose is to write something in the way most other programming languages does? :?

In the opening post you used the words:
Aacini wrote: a method that allows to use arithmetic expressions in Batch files in a way rather similar to arithmetic functions of other programming languages

I posted my suggestion before you have written:
Aacini wrote:the ability to take parameters in a way equivalent to real functions in other programming languages
Aacini wrote:The purpose is to write and execute arithmetic "functions" in a more standard way that may be comprehended by a larger group of people.
So i couldn't take the last two points into account.


I think my suggestion is similar enough; our ways to assign variables don't differ that much, so i posted it, in detail:

Code: Select all

::define: additional "[],"
set "f(x)=(x+2)"
set "g(x)=([], x+3)"

:: invoke: additional "[]="
%f(x):x=1%
%g(x):[]=x=1%
The user doesn't need to know, why "[]" is choosen (special operator) to be replaced (or he could use any other unique string to be replaced); for example he also doesn't know why in most programming languages the parameterlist is at the end of the function header: So this seemed to me less important.

Both versions are invoked in the same way: Replace a string with another (~ variable assignment).
In case of "%f(x):x=1%" the string to be replaced is mentioned within the variable name; but he has to know how to set the variable (and not doing "%f(x=1)%" or "%f(1)%").
In case of %g(x):[]=x=1% he has to know to replace "[]". If that is done for all functions it would be something that is easy to see (similar to setting x in f).

Similar for setting up a function: The user simply must know that he has to use parentheses around the formula (see: "set /A n=2 * %f(x):x=1% * 4"; result 10 versus 24), so the additional "[]," is just another fact to know
(and i initially i had my "consumer view", so i didn't made many thoughts about writing/defining the function, which was an error).


penpen

Also with your method we can use multiple arguments:

Code: Select all

@echo off
set "f(x,y)=([],x+y)"
set /a result=%f(x,y):[]="x=3,y=5"%
echo %result%


EDIT: There is also caveat in this method: %x% is set to 3 and %y% is set 5 after executing.

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

Re: Definition and use of arithmetic "functions" in Batch fi

#20 Post by Aacini » 03 Nov 2015 22:40

Well, as we can see, several different forms of using this technique are possible. For example, "args" name could be used instead of "[]" part this way:

Code: Select all

set "sum(x,y,z)=(args, x+y+z)"

set /A "sum=%sum(x,y,z):args= x=1, y=2, z=3%"

... but this is not really necessary, because the "[]" part may be completelly omitted and the value of the variables (they are not "parameters"!) may be assigned before the invocation of the "function", as you shown before:

Code: Select all

set "sum(x,y,z)=(x+y+z)"

set /A "x=2, y=3, z=4, sum=%sum(x,y,z)%"

I am pretty sure that we could develop more different ways to use this technique, and this would be very good if the purpose of this thread would be "different ways to use this method". Unfortunately, the purpose of this thread is to use this method "in a way rather similar to arithmetic functions of other programming languages", as the first line of this thread indicate. Perhaps would be a good idea to open a new thread with the other goal and move to it the posts that does not belong to this one!

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

Re: Definition and use of arithmetic "functions" in Batch fi

#21 Post by Aacini » 03 Nov 2015 22:47

There are news on this topic!


Below there is a new example that show how easy is to perform certain complex calculations when the "function" technique is combined with this expansion method to create an advanced arithmetic expression in a very simple way. I like this example!

Code: Select all

@echo off
setlocal EnableDelayedExpansion

cls
echo Polynomial evaluation
echo/
echo Enter the polynomial coefficients separated by commas.
set /P "coeffs=For example, for y=x^2-4x-7 enter 1,-4,-7:  "
echo/
set /P "range=Enter the  initial,step,final  values for x (i.e. -9,1,9):  "

rem Define the function. See: http://www.dostips.com/forum/viewtopic.php?f=3&t=6429
set "f(x)=%coeffs:,=,y=y*x+%"

echo/
echo  x    y=%f(x)%
echo ---   ------------
for /L %%x in (%range%) do (
   set /A "y=!f(x):x=%%x!"
   echo %%x    !y!
)



I devised a way to include two parameters in the function definition and correctly manage they in the expression as separate entities. After developed it, the method seems obvious: if one %expansion% was needed in order to expand the first parameter, then a %second% !expansion! is needed to expand the second one. However, the way to implement this management use an interesting trick that could be useful in other scenarios; keep the eyes wide open in order to discover it!

Code: Select all

setlocal EnableDelayedExpansion

set "Max(x,y)=(  z=(x),^!Ma1(y)"
set "Ma1(y)=?=((z-(y))>>31)+1, ?*z + ^!?*(y)  )"

set /A "max=%Max(x,y):x=10%:y=20!"

The CALL and double percents trick may also be used to define two or more parameters. For example:

Code: Select all

set "RandomRange(x,y)=(  z=(x),rnd=^!random^!,%%Random1(y)"
set "Random1(y)=((y)-z+1)*rnd/32768+z  )"

call set /A "rnd=%RandomRange(x,y):x=10%:y=20%%"

This is a complete "two parameters" example program:

Code: Select all

@echo off


:: Define Max(x,y) function with two *real* parameters

setlocal EnableDelayedExpansion

set "Max(x,y)=(  z=(x),^!Ma1(y)"
set "Ma1(y)=?=((z-(y))>>31)+1, ?*z + ^!?*(y)  )"

set /P "numbers=Enter two numbers separated by space: "
for /F "tokens=1,2" %%a in ("%numbers%") do set /A one=%%a, two=%%b

set /A "max=%Max(x,y):x=one%:y=two!"
echo The max is %max%


:: Define Max(x,y) function with two parameters via CALL/double-percents instead Delayed Expansion

set "Max(x,y)=(  z=(x),%%Ma1(y)"
set "Ma1(y)=?=((z-(y))>>31)+1, ?*z + ^!?*(y)  )"

call set /A "max=%Max(x,y):x=one%:y=two%%"
echo The max is %max% (CALL method)


:: Define RandomRange(x,y) function with two parameters via DelayedExpansion

set "RandomRange(x,y)=(  z=(x),rnd=^!random^!,^!Random1(y)"
set "Random1(y)=((y)-z+1)*rnd/32768+z  )"

set /A "rnd=%RandomRange(x,y):x=one%:y=two!"
echo Random number in this range: %rnd%


:: Define RandomRange(x,y) function with two parameters via CALL/double-percents

set "RandomRange(x,y)=(  z=(x),rnd=^!random^!,%%Random1(y)"
set "Random1(y)=((y)-z+1)*rnd/32768+z  )"

call set /A "rnd=%RandomRange(x,y):x=one%:y=two%%"
echo Random number in this range: %rnd% (CALL method)



Some of the most useful functions with two parameters are the boolean operators:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

:: Define functions for boolean operations

set "GTR(x,y)=(z=(x)-1,^!gte(y)"
set "GEQ(x,y)=(z=(x),^!gte(y)"
set "gte(y)=((z-(y))>>31)+1 )"

set "LSS(x,y)=(z=(x)+1,^!lse(y)"
set "LEQ(x,y)=(z=(x),^!lse(y)"
set "lse(y)=(((y)-z)>>31)+1 )"

set "EQU(x,y)=(z=(x),^!eq1(y)"
set "eq1(y)=^!(z-(y)) )"

set "NEQ(x,y)=(z=(x),^!ne1(y)"
set "ne1(y)=^!^!(z-(y)) )"

set /P "numbers=Enter two numbers separated by space: "
for /F "tokens=1,2" %%a in ("%numbers%") do set /A one=%%a, two=%%b

set /A "gtr=%GTR(x,y):x=one%:y=two!"
set /A "geq=%GEQ(x,y):x=one%:y=two!"
set /A "lss=%LSS(x,y):x=one%:y=two!"
set /A "leq=%LEQ(x,y):x=one%:y=two!"
set /A "equ=%EQU(x,y):x=one%:y=two!"
set /A "neq=%NEQ(x,y):x=one%:y=two!"

set "ans[0]=NOT "
echo/
echo %one% is !ans[%gtr%]!GTR than %two%
echo %one% is !ans[%geq%]!GEQ than %two%
echo %one% is !ans[%lss%]!LSS than %two%
echo %one% is !ans[%leq%]!LEQ than %two%
echo %one% is !ans[%equ%]!EQU than %two%
echo %one% is !ans[%neq%]!NEQ than %two%



As said before, the CALL/double-percent trick may be used to define more than two parameters, but we can preserve the delayed expansion in the second parameter in order to avoid excessive CALL/percents. A very good example of a function with three parameters is the if-then-else (conditional operator) one.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set "IF(test,then,else)=(  ?=(test),^!IFT(then,else)"
set "IFT(then,else)=t=(then),%%IFTE(else)"
set "IFTE(else)=^!^!?*t + ^!?*(else)  )"

set /P "value=Enter a value different than 0 for 123, or 0 for 456: "

REM      ECHO set /A "result=%IF(test,then,else):test=value%:then=123!:else=456%%"
REM CALL ECHO set /A "result=%IF(test,then,else):test=value%:then=123!:else=456%%"

call set /A "result=%IF(test,then,else):test=value%:then=123!:else=456%%"
echo Result: %result%

In this function you may see the reason because I called this method "chained expansions"; you may appreciate this behavior in a clearer way if you activate the two ECHO commands.

You may use the boolean operator functions nested in the IF function, just pay attention to the order at which the "chained expansions" occur in both functions and make adjustments if neccessary. For example:

Code: Select all

set "IF(test,then,else)=(  ?=(test),%%IFT(then,else)"
set "IFT(then,else)=t=(then),%%IFTE(else)"
set "IFTE(else)=^!^!?*t + ^!?*(else)  )"

call call call set /A "max=%%IF(test,then,else):test=%GTR(x,y):x=one%:y=two!%%:then=one%%%%:else=two%%%%%%%%"

In this line the %first% and !delayed! expansions are used for the nested GTR(x,y) function, and the rest of %expansions% (second to fourth) for the IF function; be aware that two delayed expansions can not be nested (to look at the "chained expansions", ECHO this line with no, one, two and three CALL's!)

This line is a good example of the next point: the use of IF function combined with boolean operator functions may be less efficient than the direct writting of the equivalent expression or the use of another simpler function, like Max(x,y). However, if you need to write a long and complex if-then-else expression, the use of IF function may be simpler than trying to write the equivalent expression from scratch. You may also use the IF function as starting base until the code works properly and then get the equivalent direct expression from an ECHO command inserted before the SET, although the difference in efficiency between both forms would be minimal.

Antonio

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

Re: Definition and use of arithmetic "functions" in Batch fi

#22 Post by penpen » 04 Nov 2015 05:28

OperatorGK's last edit let me notice that it might not be a good idea to change variables without limitations within a formula; examples:
- a in Abs(x)
- z in Max(x,y)
- t in IF(test,then,else)

If someone writes a library with such functions, then another user connot be sure that his variables won't change.
She/he also cannot restore these variables in the standard way (by appending ", x=%x%", or similar), because its names are unpredictable (as long as this user doesn't lookup every function).

So it might be better to use variable names of a specific format, for example variables "_1, _2, _3, ..." so the user could easily avoid using these variables.


penpen

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

Re: Definition and use of arithmetic "functions" in Batch fi

#23 Post by Aacini » 09 Nov 2015 00:20

There are very interesting news on this topic!

After defining the "function" technique I wanted to use the same method to process characters, so certain frequent manipulations (like StrLen function) could be performed in the same way. However, an arithmetic expression is performed in the same command that assign its value to a variable, but there is no such equivalent for character data. In this case the data is generated by any command and is taken and assigned to a variable via a separate FOR /F command. This way, in order to simulate the "function" method for character data we must start defining a "function" or "macro" comprised of the FOR /F required to execute a command and assign its output to a variable, like this one:

Code: Select all

set "SET(output,command)=for /F "delims=" %%a in ('command') do set "output=%%~a""

... that may be used via the same format of the "functions", that is:

Code: Select all

%SET(output,command):command=echo Hello World%
echo %output%

We may make good use of the FOR /F command and also get several lines displayed by the command and assign all of them into a long string, and enclose each line by an optional delimiter (like quotes), and even assign each line to a separate element of an array.

These SET macros may be used in combination with any command, but we may also define a "function" that perform a certain manipulation (like StrLen) specifically designed to be used inside SET macro. Below there are the definition of the two forms of SET macro (output to a single line or to an array) and a couple examples of "functions" designed for them. The main problems when writing these functions are the nesting of commands and the fact that commands placed into a nested FOR are executed in the command-line context.

Code: Select all

@echo off
setlocal EnableDelayedExpansion


rem Definition of the two basic forms of SET macro

set "_bound="
set "SET(output,command)=set "output="&(for /F "delims=" %%a in ('command') do set "output=^^^!output^^^! ^^^!_bound^^^!%%~a^^^!_bound^^^!")&set "output=^^^!output:~1^^^!""
set "SET(output[],command)=set _0=0&(for /F "delims=" %%a in ('command') do set /A _0+=1&set "output[^^^!_0^^^!]=%%~a")&set /A output.length=_0"


cls
echo Examples of use of SET macro
echo/
set "wildCard=*.*"
set /P "wildCard=Enter a wild card: "

echo/
echo List of files:
%SET(output,command):command=dir /B !wildCard!%
echo %output%

echo/
echo List of quoted files:
set _bound="
%SET(output,command):command=dir /B !wildCard!%
echo %output%

echo/
echo List of files in an array:
%SET(output[],command):command=dir /B !wildCard!%
for /L %%i in (1,1,%output.length%) do echo !output[%%i]!


echo/
echo/
echo Definition of ToUpper(str) function for SET macro
echo/
set ToUpper(str)=cmd /V:ON /C "set _0=^!str^!&(for %%a in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do @set "_0=^^^!_0:%%a=%%a^^^!")&echo "^^^!_0^^^!""
set /P "string=Enter a string: "
set "_bound="
%SET(output,command):command="!ToUpper(str):str=string!"%
echo ToUpper:        %output%


echo/
echo/
echo Definition of StrLen(str) function for SET macro
echo/
set StrLen(str)=cmd /V:ON /C "set _0=0^!str^!&>NUL set /A _1=0,_2=4096&(for /L %%i in (12,-1,0) do @>NUL set /A _3=_1+_2,_2/=2&(for /F %%n in ("^^^!_3^^^!") do @if "^^^!_0:~%%n,1^^^!" neq "" set _1=^^^!_3^^^!))&echo ^!_1^!"
set /P "string=Enter a string: "
%SET(output,command):command="!StrLen(str):str=string!"%
set "length=%output%   "

set /A tens=output/10, units=output%%10
set "ten=123456789 "
set /P "=Length: %length:~0,4%->  " < NUL
for /L %%i in (1,1,%tens%) do set /P "=%ten%" < NUL
echo(!ten:~0,%units%!

These SET macro/function combinations have the same advantages of the previous "functions": they execute faster than the original multi-line versions of the same code.

Antonio

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

Re: Definition and use of arithmetic "functions" in Batch fi

#24 Post by einstein1969 » 23 Nov 2015 09:00

Hi,

I need some assistence for a new fuction that used a previous one.

This is the my attempt to define Integer LN (Natural Logaritm) using Borchardt's algorithm :

Code: Select all

@echo off
setlocal EnableDelayedExpansion
set  "Sqrt(N)=( M=(N),x=M/(11*1024)+40, x=(M/x+x)>>1, x=(M/x+x)>>1, x=(M/x+x)>>1, x=(M/x+x)>>1, x=(M/x+x)>>1, x+=(M-x*x)>>31 )"

rem http://math.stackexchange.com/questions/75074/an-alternative-way-to-calculate-logx

for %%z in (1, 2, 3, 4, 9, 10, 16, 25, 100, 511, 512, 1000, 10000,
            65535, 65536, 100000, 131071, 131072, 262143, 262144, 393215, 393216, 800000
            1000000, 2085999, 2086000, 5000000, 10000000, 100000000, 200000000, 1000000000, 2147395600, 2147483647) do (

set /A "last_sqrt=!Sqrt(N):N=%%z!"
set /A "N=%%z, a0=(1+N)/2, b0=last_sqrt, a1=(a0+b0)/2, sqr=a1*b0"
For %%s in (!sqr!) do set /A "last_sqrt=!Sqrt(N):N=%%s!"
set /A "b1=last_sqrt, a2=(a1+b1)/2, sqr=a2*b1"
For %%s in (!sqr!) do set /A "last_sqrt=!Sqrt(N):N=%%s!"
set /A "b2=last_sqrt, a3=(a2+b2)/2, sqr=a3*b2"
For %%s in (!sqr!) do set /A "last_sqrt=!Sqrt(N):N=%%s!"
set /A "b3=last_sqrt, a4=(a3+b3)/2, sqr=a4*b3"
For %%s in (!sqr!) do set /A "last_sqrt=!Sqrt(N):N=%%s!"

set /A "N=%%z, b4=last_sqrt, ln=2*(N-1)/(a4+b4), lnp=2*(N-1)/(a3+b3)"
echo %%z ln:!ln! lnp:!lnp!
rem echo a0:!a0! b0:!b0! a1:!a1! b1:!b1! a2:!a2! b2:!b2! a3:!a3! b3:!b3! a4:!a4! b4:!b4!
rem echo(

)

pause
exit/b

There are some bugs that I will fix later...

It is possible to get a Function inside another or need more steps?

It is possible merge more steps in a single line?

Einstein1969

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

Re: Definition and use of arithmetic "functions" in Batch fi

#25 Post by einstein1969 » 24 Nov 2015 09:49

trebor68 wrote:The Sign fuction is defineted:
Value x < 0 is Sgn(x) = -1
Value x = 0 is Sgn(x) = 0
Value x > 0 is Sgn(x) = 1

See also: https://en.wikipedia.org/wiki/Sign_function

Code: Select all

D:\CMDVerz>set /a a=32,"(a>>31)+!(a>>31)*!!a"
1
D:\CMDVerz>set /a a=0,"(a>>31)+!(a>>31)*!!a"
0
D:\CMDVerz>set /a a=-32,"(a>>31)+!(a>>31)*!!a"
-1
D:\CMDVerz>


This is solution that not use the ! (for escape problem)

Code: Select all

C:\Users\ACER>set /A "n=32, s=(n>>31)|((-n>>31)&1)"
1
C:\Users\ACER>set /A "n=0, s=(n>>31)|((-n>>31)&1)"
0
C:\Users\ACER>set /A "n=-30, s=(n>>31)|((-n>>31)&1)"
-1


Einstein1969

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

Re: Definition and use of arithmetic "functions" in Batch files

#26 Post by Aacini » 16 Jul 2018 10:46

There are new developments on this topic, this time related to the definition of functions with several parameters. I strongly suggest you to review the whole thread before review this reply, in order to remember the methods used here...

Lets start with the simplest case: a function with two parameters. If a list of several expressions separated by commas is assigned to a variable in a SET /A command, the variable gets the value of the first expression, but if the list is enclosed in parentheses, then the variable gets the value of the last expression. This behavior allows to define a function with two parameters and easily separate them by just enclosing the parameters pair between parentheses in order to get the second parameter:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Definition of a function with two numeric parameters
set "TwoParams(x,y)= x=x,y , y=(x,y)"

rem Usage example
set /A "test=%TwoParams(x,y):x,y=123,456%"
echo x=%x%, y=%y%


rem Practical example: MAXimum and MINimum functions
set "Max(x,y)=( x=x,y, y=(x,y), c=(x-y>>31)+1, c*x+^^^!c*y )"
set "Min(x,y)=!Max(x,y):x-y=y-x!"

echo/
set /P "numbers=Enter two numbers separated by a space: "
set /A "n1=%numbers: =,n2=%, max=%Max(x,y):x,y=n1,n2%, min=%Min(x,y):x,y=n1,n2%"
echo Max = %max%,  Min = %min%


rem Practical example: Add/Subtract two "1+six_digits" values representing times

rem Definition of the AddTimes function with two "1HHMMSS" parameters
set "AddTimes(t1,t2)=( t1=t1,t2,t2=(t1,t2), s1=t1%%100,t1/=100,s1+=t1%%100*60,t1/=100,s1+=t1%%100*60*60, s2=t2%%100,t2/=100,s2+=t2%%100*60,t2/=100,s2+=t2%%100*60*60, r=s1+s2, res=r%%60,r/=60,res+=r%%60*100,r/=60,res+(r+100)*10000 )"
rem Definition of the derived SubTimes function
set "SubTimes(t1,t2)=!AddTimes(t1,t2):s1+s2=s1-s2!"

echo/
set /P "time1=Enter base time in HH:MM:SS format: "
set /P "time2=Enter delta time, same format:      "
set /A "add=!AddTimes(t1,t2):t1,t2=1%time1::=%,1%time2::=%!, sub=!SubTimes(t1,t2):t1,t2=1%time1::=%,1%time2::=%!"
echo                                    ---------
echo                  The Add result is: %add:~-6,2%:%add:~-4,2%:%add:~-2%
echo                                    ---------
echo                  The Sub result is: %sub:~-6,2%:%sub:~-4,2%:%sub:~-2%
Output:

Code: Select all

x=123, y=456

Enter two numbers separated by a space: 123 456
Max = 456,  Min = 123

Enter base time in HH:MM:SS format: 10:45:15
Enter delta time, same format:      00:30:30
                                   ---------
                 The Add result is: 11:15:45
                                   ---------
                 The Sub result is: 10:14:45
A "SET /A" arithmetic expression don't provides a method to separate more than two parameters, so we need to use the standard "SET" tricks in order to do so. Although doing that will not return a result in the simple and direct way than the numeric "SET /A" does, this non-numeric "function" provides a method to encapsulate in a single line a series of managements that are used in a very simple way, that is the original purpose of this thread anyway. Besides, the use of standard SET command allows to manage non-numeric parameters.

The method used to separate an "a,b,c" parameter list in individual "a", "b", "c" elements is explained with detail at this post.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Definition of a non-numeric "function" with three parameters
set SetVars(a,b,c)=set "a=a,b,c" ^& set "b=^!a:*,=^!" ^& call set "a=%%a:,^!b^!=%%" ^& set "c=^!b:*,=^!" ^& call set "b=%%b:,^!c^!=%%"

rem Usage examples

%SetVars(a,b,c):a,b,c=10,20,30%
echo Three numeric values: a="%a%", b="%b%", c="%c%"

%SetVars(a,b,c):a,b,c=First value,This is the second value,And this is the last one%
echo Three string values: a="%a%", b="%b%", c="%c%"
Output:

Code: Select all

Three numeric values: a="10", b="20", c="30"
Three string values: a="First value", b="This is the second value", c="And this is the last one"
Note that the definition of SetVars "function" follows a well defined scheme. This point means that the creation of a function of this type with any number of parameters could be automatized via a subroutine:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Example of automatized definition of a "function" with four parameters
call :DefineSetVars a b c d
echo Defined function:
echo SetVars(a,b,c,d)=!SetVars(a,b,c,d)!

rem Usage example
%SetVars(a,b,c,d):a,b,c,d=10,20,30,40%
echo Four numeric values: a="%a%", b="%b%", c="%c%", d="%d%"

goto :EOF

rem Subroutine to create a base "function" with several parameters

:DefineSetVars var1 var2 var3 ...
setlocal EnableDelayedExpansion

set "last="
for %%a in (%*) do (
   if not defined last (
      set "expr=%*"
      set "expr=!expr: =,!"
      set expr=SetVars(!expr!^)=set "%%a=!expr!"
   ) else (
      set expr=!expr! ^& set "%%a=^^^!!last!:*,=^^^!" ^& call set "!last!=%%!last!:,^^^!%%a^^^!=%%"
   )
   set "last=%%a"
)
for /F "delims=" %%a in ("!expr!") do (
   endlocal
   set "%%a"
)
exit /B
Output:

Code: Select all

Defined function:
SetVars(a,b,c,d)=set "a=a,b,c,d" & set "b=!a:*,=!" & call set "a=%a:,!b!=%" & set "c=!b:*,=!" & call set "b=%b:,!c!=%" & set "d=!c:*,=!" & call set "c=%c:,!d!=%"
Four numeric values: a="10", b="20", c="30", d="40"
Finally, lets review a different example: instead of define a function with several parameters, lets define a function with one parameter that is the name of a variable, and process it as a string in a very different way:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Define the StrLen(var) "function" with one string *variable* as parameter
set StrLen(var)=set "str=0^!var^!" ^& set /A "l=0,n=b=1<<12"
for /L %%i in (1,1,13) do set StrLen(var)=!StrLen(var)! ^& call set "c=%%str:~^!n^!,1%%" ^& (if "^!c^!" neq "" set /A l=n) ^& set /A "n=l+(b>>=1)"
set StrLen(var)=!StrLen(var)! ^& set /A "StrLen=l"

rem Example of use of StrLen(var) function
:loop
   set "str="
   set /P "str=Enter a string: "
   if not defined str goto :EOF
   %StrLen(var):var=str%
   echo The length is:  %StrLen%
   echo/
goto loop
Output:

Code: Select all

Enter a string: Nineteen characters
The length is:  19

Enter a string: TenLetters
The length is:  10

Enter a string:
Antonio

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

Re: Definition and use of arithmetic "functions" in Batch files

#27 Post by aGerman » 16 Jul 2018 17:23

This is syntactic sugar :lol: Thanks for sharing.

Steffen

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

Re: Definition and use of arithmetic "functions" in Batch files

#28 Post by einstein1969 » 27 Mar 2021 03:26

Hi,

there is an error on function:

Code: Select all

set "CSecToHMSC(CSec)=( a=(CSec), c=a%%100, a/=100, s=a%%3600, a/=3600, m=a%%60, h=a/60, h*1000000+m*10000+s*100+c )"
it should be

Code: Select all

set "CSecToHMSC(CSec)=( a=(CSec), c=a%%100, a/=100, s=a%%60, a/=60, m=a%%60, h=a/60, h*1000000+m*10000+s*100+c )"
can someone confirm?

Post Reply