Definition and use of arithmetic "functions" in Batch files

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

Definition and use of arithmetic "functions" in Batch files

#1 Post by Aacini » 26 Oct 2015 21:16

In this thread I present a method that allows to use arithmetic expressions in Batch files in a way rather similar to arithmetic functions of other programming languages. Let's start with a ":Rand x result" subroutine that in regular Batch code would be written this way:

Code: Select all

:Rand x result
set /A %2=%1 * %random% / 32768 + 1
exit /B
... and used this way:

Code: Select all

call :Rand 25 num
echo Random number between 1 and 25: %num%
This code can be converted into a "function" via a variable with "function(arg)" name and the arithmetic expression that calculate the result as value. For example:

Code: Select all

set "Rand(x)=x * ^!random^! / 32768 + 1"
To invoke this "function", you should use this format:

Code: Select all

set /A num=%Rand(x):x=25%
echo Random number between 1 and 25: %num%
Although this example seems to be practically the same than previous one, the function method run faster because it does not require CALL command. Besides, a "function" called this way may work as a true function, so it may be placed into a larger expression and the parameter may be an arithmetic expression. To successfully achieve these points, just enclose in parentheses the whole expression and the parameter. For example:

Code: Select all

set "Rand(x)=( (x)*^!random^!/32768+1 )"

set /A num=%Rand(x):x=5*6% + 10
echo Random number between 11 and 40: %num%
Below there are two simple function examples: Sign function returns -1 if the argument is negative, and 1 otherwise; Abs function use the sign of the argument to get its absolute value.

Code: Select all

set "Sign(x)=((x)>>31|1)"
set "Abs(x)=(((x)>>31|1)*(x))"
An important feature in the definition of these functions is the comma operator that allows to perform a series of partial calculations with different variables and use they in the final calculation. For example, Abs function may be defined as shown below; if it is called with a large expression, the argument is evaluated just once:

Code: Select all

set "Abs(x)=(a=(x), (a>>31|1)*a)
There are several tricks that allows to use additional features in the definition of a function. For example, the value of "a-123" is positive or zero if "a" is greater or equal 123, so "((a-123)>>31)+1" subexpression is 1 if "a" is greater or equal 123 and 0 otherwise. This method allows to implement an if-then-else feature equivalent to C++ "?:" conditional operator via a large expression comprised of three parts: previous subexpression (that we may call "condition"), the "then" value multiplied by the condition and the "else" value multiplied by the NOT condition, and add the two last parts.

In the manipulation of the 0 and 1 values returned by conditions the multiplication may work as AND boolean operator, addition may work as OR, and exclamation-mark works as NOT. The expression "!!value" is 0 if "value" is 0 and is 1 otherwise, so it may be used to reduce several values accumulated by addition operator (OR) into a single 1. You may also use "&", "|" and "^" bitwise operators for AND, OR and XOR boolean operators, respectively, that directly gives proper results when the values are 0 or 1.

The Max function below get the maximum of two values. We can use one parameter only, so we need to place the other value in a variable:

Code: Select all

REM  Max1(x)=  if (x geq y)  then x    else y
set "Max1(x)=( ?=((x-y)>>31)+1, ?*x + ^^^!?*y )"

set /P "pair=Enter two numbers separated by space: "
for /F "tokens=1,2" %%a in ("%pair%") do set /A "a=%%a, b=%%b"
set /A "y=b, max=%Max1(x):x=a%"         // or: set /A "max=(y=b, %Max1(x):x=a%)"
echo The max is: %max%
Note that it is necessary to escape the exclamation-mark (NOT operator) with three carets if delayed expansion is enabled when the function is defined.

In certain cases we can simulate two arguments in a function if algebraic manipulations allows it; this depends on the specific formula used in the calculation. The function below is the Max function with two arguments:

Code: Select all

set "Max(x,y)=( ?=((x,y)>>31)+1, ?*(2*x,y-(x,y)) + ^^^!?*(x,y-(x,y*2)) )"
In this case we insert the missing subtraction operation in the invocation itself:

Code: Select all

set /A "max=%Max(x,y):x,y=one-two%"
echo The max of %one% and %two% is: %max%
The explanation of this code "is obvious" (as jeb would say! :wink: ), just use a little basic algebra... Note that in Batch files, differently than in other languages, the same name may be used in both a variable and a function (of course, the explanation is that "name" and "name(x)" are different variables).

The conversion functions from HHMMSSCC time to centiseconds and viceversa are straightforward:

Code: Select all

set "HMSCtoCSec(HMSC)=( a=(HMSC), h=a/1000000, a%%=1000000, m=a/10000, a%%=10000, s=a/100, c=a%%100, ((h*60+m)*60+s)*100+c )"
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 )"

echo %time% & for /F "tokens=1-4 delims=:." %%a in ("%time%") do set "startTime=%%a%%b%%c%%d"
place here any process
echo %time% & for /F "tokens=1-4 delims=:." %%a in ("%time%") do set "endTime=%%a%%b%%c%%d"
set /A "elapsed=%TimeToCSec(HMSC):HMSC=endTime% - %TimeToCSec(HMSC):HMSC=startTime%"
echo Elapsed time: %elapsed:~0,-2%.%elapsed:~-2% seconds
The conversion functions from YYYYMMDD date to Julian Day Number and viceversa are very useful. You may review the original Batch code for these functions here.

Code: Select all

set "DateToJDN(YMD)=( a=(YMD), y=a/10000, a%%=10000, m=a/100, d=a%%100, a=(m-14)/12, (1461*(y+4800+a))/4+(367*(m-2-12*a))/12-(3*((y+4900+a)/100))/4+d-32075 )"
set "JDNtoDate(JDN)=( a=(JDN), l=a+68569,n=(4*l)/146097,l=l-(146097*n+3)/4,i=(4000*(l+1))/1461001,l=l-(1461*i)/4+31,j=(80*l)/2447,d=l-(2447*j)/80,l=j/11,m=j+2-(12*l),y=100*(n-49)+i+l,y*10000+m*100+d )"

set /P "otherDate=Enter a date in YYYY/MM/DD format: "
for /F "tokens=1-3 delims=/" %%a in ("%date%") do set "today=%%c%%a%%b"
set /A "days=%DateToJDN(YMD):YMD=today% - %DateToJDN(YMD):YMD=!otherDate:/=!%"
echo/
echo There are %days% days between that date and today
Below there is a complete Batch file that includes all previous examples, so you don't need to copy each one of they in order to test them.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Definition and use of arithmetic "functions" in Batch files
rem http://www.dostips.com/forum/viewtopic.php?f=3&t=6744
rem Antonio Perez Ayala


:: Define Rand(x) function
set "Rand(x)=x * ^!random^! / 32768 + 1"

:: Use Rand(x) function
set /A num=%Rand(x):x=25%
echo Random number between 1 and 25: %num%


:: Define Rand(x) to be used as a true function
set "Rand(x)=( (x)*!random!/32768+1 )"
set /A num=%Rand(x):x=5*6% + 10
echo Random number between 11 and 40: %num%


:: Define Max1(x) function with one parameter and one variable
REM  Max1(x)=  if (x geq y)  then x    else y
set "Max1(x)=( ?=((x-y)>>31)+1, ?*x + ^^^!?*y )"

echo/
echo Max1(x) function test
:nextPair1
   set "pair="
   set /P "pair=Enter two numbers separated by space: "
   if not defined pair goto endPair1
   for /F "tokens=1,2" %%a in ("%pair%") do set /A "a=%%a, b=%%b"
   set /A "max=(y=b, %Max1(x):x=a%)"
   echo The max is: %max%
goto nextPair1
:endPair1


:: Define Max(x,y) and Min(x,y) functions with two parameters
set "Max(x,y)=( ?=((x,y)>>31)+1, ?*(2*x,y-(x,y)) + ^^^!?*(x,y-(x,y*2)) )"
set "Min(x,y)=( ?=((x,y)>>31)+1, ?*(x,y-(x,y*2)) + ^^^!?*(2*x,y-(x,y)) )"

echo/
echo Max(x,y) function test
:nextPair
   set "pair="
   set /P "pair=Enter two numbers separated by space: "
   if not defined pair goto endPair
   for /F "tokens=1,2" %%a in ("%pair%") do set /A "a=%%a, b=%%b"
   set /A "max=%Max(x,y):x,y=a-b%"
   echo The max is: %max%
goto nextPair
:endPair


:: Define HHMMSSCC time to centiseconds conversion function and viceversa

set "TimeToCSec(HMSC)=( a=(HMSC), h=a/1000000, a%%=1000000, m=a/10000, a%%=10000, s=a/100, c=a%%100, ((h*60+m)*60+s)*100+c )"
set "CSecToTime(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 )"


:: Define YYYYMMDD date to Julian Day Number conversion function and viceversa

set "DateToJDN(YMD)=( a=(YMD), y=a/10000, a%%=10000, m=a/100, d=a%%100, a=(m-14)/12, (1461*(y+4800+a))/4+(367*(m-2-12*a))/12-(3*((y+4900+a)/100))/4+d-32075 )"
set "JDNtoDate(JDN)=( a=(JDN), l=a+68569,n=(4*l)/146097,l=l-(146097*n+3)/4,i=(4000*(l+1))/1461001,l=l-(1461*i)/4+31,j=(80*l)/2447,d=l-(2447*j)/80,l=j/11,m=j+2-(12*l),y=100*(n-49)+i+l,y*10000+m*100+d )"


echo/
echo %time% & for /F "tokens=1-4 delims=:." %%a in ("%time%") do set "startTime=%%a%%b%%c%%d"
set /P "birthDate=Enter your birthdate in YYYY/MM/DD format: "
echo %time% & for /F "tokens=1-4 delims=:." %%a in ("%time%") do set "endTime=%%a%%b%%c%%d"
set /A "elapsed=%TimeToCSec(HMSC):HMSC=endTime% - %TimeToCSec(HMSC):HMSC=startTime%"
echo/
echo You took %elapsed:~0,-2%.%elapsed:~-2% seconds to enter previous line

REM As usual, you must adjust the next line accordingly to your locale date format
for /F "tokens=1-3 delims=/" %%a in ("%date%") do set "today=%%c%%a%%b"
set /A "total=%DateToJDN(YMD):YMD=today% - %DateToJDN(YMD):YMD=!birthDate:/=!%, a=total*100, years=a/36525, a%%=36525, months=a/3060, days=(a%%3060)/100"
echo/
echo You are %total% days old (%years% years, %months% months and %days% days approx.)
Enjoy it! :D

Antonio

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

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

#2 Post by OperatorGK » 27 Oct 2015 01:15

Can they be nested?

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

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

#3 Post by einstein1969 » 27 Oct 2015 05:41

Nice!

Squashman
Expert
Posts: 4153
Joined: 23 Dec 2011 13:59

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

#4 Post by Squashman » 27 Oct 2015 06:43

I have gotten confused enough trying to interpret all the threads about Macros. Is this not essentially a Macro and not a function? At least that was my understanding of the definition from reading all those threads.

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

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

#5 Post by jeb » 27 Oct 2015 06:46

@Aacini

Cool stuff :o
Your solution looks so easy (nearly obvious :wink: ), I wonder why nobody developed it before. :D

OperatorGK wrote:Can they be nested?

I think that isn't possible, as you need to use the variable replace syntax.
You could use at best percent and delayed expansion to nest one function into another one, but not more.

Jer
Posts: 160
Joined: 23 Nov 2014 17:13
Location: California USA

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

#6 Post by Jer » 27 Oct 2015 19:37

Any idea why I get the missing operand error?
My O/S is Window 7 32-bit

C:\Temp>Setlocal EnableDelayedExpansion

C:\Temp>REM Max1(x)= if (x geq y) then x else y

C:\Temp>set "Max1(x)=( ?=((x-y)>>31)+1, ?*x + ^^^!?*y )"

C:\Temp>set /P "pair=Enter two numbers separated by space: "
Enter two numbers separated by space: 50 100

C:\Temp>for /F "tokens=1,2" %a in ("50 100") do set /A "a=%a, b=%b"

C:\Temp>set /A "a=50, b=100"

C:\Temp>set /A "y=b, max=( ?=((a-y)>>31)+1, ?*a + ^!?*y )" // or: set /A "max=(y=b, ( ?=(
)+1, ?*a + ^!?*y ))"
Missing operand.

C:\Temp>echo The max is:
The max is:

C:\Temp>endlocal
C:\Temp>

Code: Select all

@Echo On
Setlocal EnableDelayedExpansion
REM  Max1(x)=  if (x geq y)  then x    else y
set "Max1(x)=( ?=((x-y)>>31)+1, ?*x + ^^^!?*y )"

set /P "pair=Enter two numbers separated by space: "
for /F "tokens=1,2" %%a in ("%pair%") do set /A "a=%%a, b=%%b"
set /A "y=b, max=%Max1(x):x=a%"         // or: set /A "max=(y=b, %Max1(x):x=a%)"
echo The max is: %max%
endlocal

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

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

#7 Post by penpen » 28 Oct 2015 03:42

Jer wrote:Any idea why I get the missing operand error?
Jer wrote:set /A "y=b, max=%Max1(x):x=a%" // or: set /A "max=(y=b, %Max1(x):x=a%)"
The "//" part causes this issue, because the slash ('/') is an operator (division).
If you use it an operand is expected (here: divisor) but not present (a second divison operator follows.

It's a flaw in Aacini's how-to-use-code (probably because "//" is an c-style comment):
Just replace the "//" with "& rem" and it should work.

Aacini wrote:We can use one parameter only, so we need to place the other value in a variable
You could also assign more than one variable if yoiu replace an unused one:

Code: Select all

@echo off
setlocal
rem setup formula
set "sum(x,y,z)=([], x+y+z)"


rem set 3 parameters
set /A "sum=%sum(x,y,z):[]=x=1, y=2, z=3%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem simulate parameters using variables
set /A "x=2, y=3, z=4, sum=%sum(x,y,z)%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem one parameter and some variables
set /A "x=3, y=4, sum=%sum(x,y,z):[]=z=5%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem of course the order is not important
set /A "y=5, sum=%sum(x,y,z):[]=z=6,x=4%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

endlocal
This initialization is of advantage especially if the name of one variable is contained in another (example: "x" and "dx").
The doublequotes are important, if you access the formula because the brackets ("[]") are special characters and should be treated as one variable, but you could also use any other.


penpen

trebor68
Posts: 146
Joined: 01 Jul 2011 08:47

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

#8 Post by trebor68 » 28 Oct 2015 18:38

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>

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

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

#9 Post by Aacini » 28 Oct 2015 19:06

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


Yes. Strictly speaking, you are right. However, the Sign function was one of the first ones in my description, so I did not wanted to insert additional complications in my description so early...

The Sign function may be written in a slightly simpler way, and you may use a "function" directly at the command line:

Code: Select all

C:\> set "Sign(a)=(a>>31|1)*!!a"

C:\> set /A "%Sign(a):a=32%"
1
C:\> set /A "%Sign(a):a=0%"
0
C:\> set /A "%Sign(a):a=-32%"
-1

You may review a practical use of the original formula (not correct, but reduced form) of Sign function at this post.

Antonio

Samir
Posts: 358
Joined: 16 Jul 2013 12:00
Location: HSV
Contact:

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

#10 Post by Samir » 30 Oct 2015 10:27

Simple amazing. I study your post like I used to study my C book in college. Thank you for sharing!

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

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

#11 Post by Aacini » 31 Oct 2015 14:38

Squashman wrote:I have gotten confused enough trying to interpret all the threads about Macros. Is this not essentially a Macro and not a function? At least that was my understanding of the definition from reading all those threads.

Well, strictly speaking all expansions of variables that contain code instead of data are macros! However, these ones have an unique feature not used before in any type of macro: the ability to take parameters in a way equivalent to real functions in other programming languages; that is the main reason I call them "functions".



jeb wrote:
OperatorGK wrote:Can they be nested?


I think that isn't possible, as you need to use the variable replace syntax.
You could use at best percent and delayed expansion to nest one function into another one, but not more.

Yes, jeb; here it is an example of a two-level nesting functions based on %double !expansion!%:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

:: Define YYYYMMDD date to Julian Day Number conversion function and viceversa

set "DateToJDN(YMD)=( a=(YMD), y=a/10000, a%%=10000, m=a/100, d=a%%100, a=(m-14)/12, (1461*(y+4800+a))/4+(367*(m-2-12*a))/12-(3*((y+4900+a)/100))/4+d-32075 )"
set "JDNtoDate(JDN)=( a=(JDN), l=a+68569,n=(4*l)/146097,l=l-(146097*n+3)/4,i=(4000*(l+1))/1461001,l=l-(1461*i)/4+31,j=(80*l)/2447,d=l-(2447*j)/80,l=j/11,m=j+2-(12*l),y=100*(n-49)+i+l,y*10000+m*100+d )"

echo/
echo Two-level nesting function test
rem Adjust next line for your locale date format
for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
    set "today=%%c%%b%%a"
    echo Today is %%c/%%b/%%a in YYYY/MM/DD format
)
:nextDays
   echo/
   set "days="
   set /P "days=Enter a number of days: "
   if not defined days goto endDays
   rem     newDate =  JDNtoDate(           DateToJDN(         today) + days )
   set /A "newDate = %JDNtoDate(JDN):JDN= !DateToJDN(YMD):YMD=today! + days %"
   echo Today + %days% days = %newDate:~0,4%/%newDate:~4,2%/%newDate:~6,2%
goto nextDays
:endDays

However, you may also have several expansion levels using multiple call commands and duplicating the number of percent signs in each nesting function, although the result may look somewhat confusing! The program below is just an example of this technique, with no usefulness at all:

Code: Select all

@echo off
setlocal

rem Define a function that works as an operator
set "OP(x,y)=(x,y)"

rem result =            (                  (              (            10+20) * (            30+40)  )  -  100      )
rem operators per function:     -                *             +                     +
CALL CALL set /A result=%%%%OP(x,y):x,y=   %%OP(x,y):x,y= %OP(x,y):x,y=10+20% * %OP(x,y):x,y=30+40% %%  -  100   %%%%

echo Result = %result%






penpen wrote:
Aacini wrote:We can use one parameter only, so we need to place the other value in a variable

You could also assign more than one variable if yoiu replace an unused one:

Code: Select all

@echo off
setlocal

rem setup formula
set "sum(x,y,z)=([], x+y+z)"

rem set 3 parameters
set /A "sum=%sum(x,y,z):[]=x=1, y=2, z=3%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem simulate parameters using variables
set /A "x=2, y=3, z=4, sum=%sum(x,y,z)%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem one parameter and some variables
set /A "x=3, y=4, sum=%sum(x,y,z):[]=z=5%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem of course the order is not important
set /A "y=5, sum=%sum(x,y,z):[]=z=6,x=4%"
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]


Wow! This is the type of details I love about a new development: that it may serve as base for new developments! Although your example is interesting, there is a fundamental concept missing on it: the parameter. As I said in my answer to Squashman, the keypoint that makes these "functions" unique are its ability to take parameters in a way equivalent to functions in other programming languages. In your example the "parameters" are totally useless because the same behavior and result may be obtained with less, more of different named parameters in the definition, or with no parameters at all. For example:

Code: Select all

rem setup formula with 3 "parameters"
set "sum(x,y,z)=([], x+y+z)"

rem set 3 parameters
set /A "sum=%sum(x,y,z):[]=x=1, y=2, z=3%"
echo 3 parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem setup formula with no parameters
set "sum()=([], x+y+z)"

rem the same...
set /A "sum=%sum():[]=x=1, y=2, z=3%"
echo No parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem setup formula with whichever parameters
set "sum(O,PQ,RST,UVWXYZ)=([], x+y+z)"

rem the same...
set /A "sum=%sum(O,PQ,RST,UVWXYZ):[]=x=1, y=2, z=3%"
echo Whichever parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

The method you used to assign the value to the "parameters" before invoke the function may suggest another way to use this feature. For example, instead of define a function with a fixed formula that process the values of changing parameters, we could define a formula over fixed variables ("pseudo-parameters") and change the operations in the formula via the real parameters. For example:

Code: Select all

rem Define a general-purpose function with 4 "pseudo-parameters":
set "accum4(x,y,z,t)=x,y,z,t"

set /A "x=2,y=4,z=6,t=8, sum=%accum4(x,y,z,t):,=+%"
echo The sum of %x%+%y%+%z%+%t% is %sum%

set /A "x=2,y=4,z=6,t=8, prod=%accum4(x,y,z,t):,=*%"
echo The product of %x%*%y%*%z%*%t% is %prod%

However, this method is just an interesting curiosity that have not practical use...

Antonio

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

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

#12 Post by penpen » 31 Oct 2015 17:30

Aacini wrote:the keypoint that makes these "functions" unique are its ability to take parameters in a way equivalent to functions in other programming languages. In your example the "parameters" are totally useless because the same behavior and result may be obtained with less, more of different named parameters in the definition, or with no parameters at all. For example:

Code: Select all

rem setup formula with 3 "parameters"
set "sum(x,y,z)=([], x+y+z)"

rem set 3 parameters
set /A "sum=%sum(x,y,z):[]=x=1, y=2, z=3%"
echo 3 parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem setup formula with no parameters
set "sum()=([], x+y+z)"

rem the same...
set /A "sum=%sum():[]=x=1, y=2, z=3%"
echo No parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

rem setup formula with whichever parameters
set "sum(O,PQ,RST,UVWXYZ)=([], x+y+z)"

rem the same...
set /A "sum=%sum(O,PQ,RST,UVWXYZ):[]=x=1, y=2, z=3%"
echo Whichever parameters:
echo sum==%sum%==x[x=%x%]+y[y=%y%]+z[z=%z%]

I don't understand... .
I fear i miss your keypoint.

The name of any variable is never part of its content.
That is also true for all your functions (example):

Code: Select all

set "Rand(x)=x * ^!random^! / 32768 + 1"
set /A num=%Rand(x):x=25%
echo %num%

set "Rand()=x * ^!random^! / 32768 + 1"
set /A num=%Rand():x=25%
echo %num%

set "Rand(OPQ)=x * ^!random^! / 32768 + 1"
set /A num=%Rand(OPQ):x=25%
echo %num%


penpen

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

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

#13 Post by Aacini » 31 Oct 2015 23:54

penpen wrote:I don't understand... .
I fear i miss your keypoint.


Well, perhaps would be convenient to review what I said about this point:
on viewtopic.php?f=3&t=6744&p=43622#p43622 Aacini wrote:In this thread I present a method that allows to use arithmetic expressions in Batch files in a way rather similar to arithmetic functions of other programming languages.

on viewtopic.php?f=3&t=6744&p=43737#p43737 Aacini wrote:... these ones have an unique feature not used before in any type of macro: the ability to take parameters in a way equivalent to real functions in other programming languages.

The purpose of this thread is not to perform arithmetic operations in an "advanced", "complex" or just different way. The purpose is to write and execute arithmetic "functions" in a more standard way that may be comprehended by a larger group of people.

I think the next lines are clear enough to be understood by most programmers even if they know nothing about Batch files:

Code: Select all

set "Rand(x)=x * ^!random^! / 32768 + 1

set /A num=%Rand(x):x=25%

The format of the definition is entirely standard: "function(arg) as name and the arithmetic expression that calculate the result as value" with the argument of the function included in the expression.

The invocation is a little bit tricky when compared vs. the standard format: the value of the parameter is not placed in parentheses, but the original argument is repeated and its value is "assigned" after the colon. However, IMO this method would still be understood by many programmers with no additional or very little explanation ("Execute Rand(x) with x=25").

Now, let's review the first of your examples:

Code: Select all

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

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

I invite you to try to explain this code to someone that does not know Batch files! Even an experienced Batch programmer may be confused by the "([], " part (starting with me!). What these characters means? Is it a Batch file feature that represent the parameter list? Is it an empty array (like in JavaScript) that receive the parameters? Of course, when the trick is understood we realize that there is nothing special about it, but it is a fact that this format is confusing and that we must do an additional effort in order to understand it.

In your next examples we can see that in the function invocation we can omit some parameters or even all of them. Why an error is not issued in these cases? If the declared parameters have not any effect in the way the function can be invoked, what is the purpose to declare them? As you note it, my format MAY also be invoked this way, but the keypoint of this topic is to write and execute functions in the standard way. I do not recommend to write code that does not conform to the standards; I encourage to always define and use functions using the standard format even if we know this is not required.

This thread provides a programming tool that aids in writting clearer and better Batch programs, when is used correctly.

Antonio

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

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

#14 Post by penpen » 01 Nov 2015 08:54

I reviewed especially these lines multiple times before creating my above post. It didn't occurred to me that writing the function is also "using" it (until now; still not fully sure about that).

I had some sort of "consumer view" because you have also used nonstandard notation: For example in your Max(x,y) where you assigned the second value to the result which is not possible for most programming languages; my suggestion does the same to add an unused (but more or less well known; i fear less...) variable named "[]" (==substitution operator; see sidenote at the bottom of this post).

You could also use any other variable name if that is the problem: Actually i have no idea of a name that is meaningfull for both writing the function and replacing it with parameter values; maybe "setparams" or ":":

Code: Select all

set "f(x,y)=(setparams, x+y+4)"
set /A "z=%f(x,y):setparams=(x=1, y=2)%"
echo %z%

set "g(n)=(:, n-3)"
set /A "a=%g(n)::=(g=4)%"
echo %a%
But actually i think, it is also no good solution (to this task).

(
Actally i think the most compatible solution could only be produced by adding another macro; maybe named "SET", that autodetects used formulas and checks its parameters:

Code: Select all

:set "set=???"
set "g(x)=x+1"
%set% /A "n=g(4)+100*g(5)"

)

Aacini wrote:In your next examples we can see that in the function invocation we can omit some parameters or even all of them. Why an error is not issued in these cases? If the declared parameters have not any effect in the way the function can be invoked, what is the purpose to declare them?
I think i don't need to respect these points because my suggestion shouldn't solve these issues (only "invoke" the function with multiple variables instead of only 1).


Aacini wrote:Even an experienced Batch programmer may be confused by the "([], " part (starting with me!). What these characters means?
The square brackets ('[', ']') have no special meaning for the "set /A" command, so they are treated as a variable name just like "x", or "?".


Sidenote:
From what i above called "consumer view" my usage of square brackets ("[]") is motivated by a C++ precompiler we used at university (sorry, i even don't know its name anymore).
I must admit i never heard of a programming language that "naturally" supports this operator.
This precompiler handles the mathematical substitution operator, so this notation is not completely unknown (but indeed nearly - outside the math world - and even there it may be unknown to some: Depends on their subject field.).

Although it is valid to use this operator in all areas of mathematics it is mostly not used because:
- avoiding it is too easy (just say "now substitute x by y+1"), and
- the formal definition of this operator is tricky, if not introducing "Lambda calculus"
See https://en.wikipedia.org/wiki/Lambda_calculus.

Empty brackets represents an empty substitution (so nothing is substituted), so
- "f(x)[]" equals "f(x)"
- "f(x)[x=2]" equals "f(2)[]" equals "f(2)".

I first wanted to use %f(x):[]=[x=1]% to replace the empty substitution with the substitution of x with 1:
It should represent "f(x)[x=1]".

But that is bad, because in batch "[x" is interpreted as a variable name and "1]" is no valid formula, so i left the brackets on the right side.
You could use "[,]" (a list of two empty substitutions and add "x=1," to be correct in mathematical terms), but that is very unusual and looks just ugly:

Code: Select all

set "succ(n)=([,],n+1)"
set /A "m=%succ(n):[,]=[,n=1,]%"


penpen

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

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

#15 Post by OperatorGK » 01 Nov 2015 10:32

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

Isn't this basically batch %x:y=z% operator? The only difference, AFAIK, is that [] operator may be used in anonymous expressions.

Post Reply