math.cmd: a math expression parser written in native WinNT batch script

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
CirothUngol
Posts: 46
Joined: 13 Sep 2017 18:37

math.cmd: a math expression parser written in native WinNT batch script

#1 Post by CirothUngol » 16 Sep 2017 02:46

OK, I'm ready to start trying to optimize my latest script with some of the goodies found here at Dostips, but before I go tinkering with tools that I know precious little about and wind up wrecking what is at the moment a mostly complete and seemingly working batch script, I thought I might post it here and ask others to play with it and hopefully find any obvious bugs or glaring errors it may have. I'd like to correct or add such stuff while re-writing to accommodate my introduction to (multi-line) macros. It spends most of it's time in loops, but I figure a few macros couldn't hurt... besides, they look like fun! ^_^

So, once upon a time I needed to compare really big numbers in batch (file sizes). I found a nice little COMPARE utility by Brian Williams and liked how clever it was. He also wrote ADD (which I also needed) and MULTIPLY (which I did not need) utilities for really big numbers, which I also liked for their cleverness... so I re-wrote them to try and make them clever-er. Then I thought... that's two out of four. If I added subtraction and division... there's really nothing that couldn't be done (mathematically speaking), right?

math.cmd is an 'expression parser' because I saw the term while researching the shunting-yard algorithm and thought it sounded brainy, I'm not even sure it's true. It uses brute-force style string manipulation to add, subtract, multiply, and divide insanely large decimal numbers (probably thousands of digits), and the parser accepts parenthesis, functions, assignments, etc. I was nearly done with optimizations, but now the only ones left require macros so here's my before shot... let's see how much faster some macros can make it. Brief word of warning, I'm not a math guy. I had to (at least minimally) research the procedure for literally everything here except addition, and the shunting-yard algorithm is ~90% straight pseudo-code. Run with no options or double-click to bring up the help screens, there's a little interactive bit at the end.
Here's the help screens, zipped file is below.

Code: Select all

:math [/An|/Dn|/Mn|/Rn|/Sn|/Un|/H|/?] In-line_Math_Expression [;...]       v0.2
::
:: Full-featured expression parser written in 100% native WinNT batch script.
:: Supports functions, assignments, numbers to thousands of decimal places,
:: and provides the following full range of operators in order of precedence:
::
:: Highest : $ Exponent : & NthRoot
::         : * Multiply : / Divide : @ Modulus
::         : + Addition : - Subtraction
::         : <=> Raw Compare (returns 1=greater, -1=less, 0=equals)
::         : < LessThan : > GreaterThan : <= LessOrEqual : >= GreaterOrEqual
::         : ## EqualTo : <> NotEqualTo (comparisons return 1=true, 0=false)
:: Lowest  : = Equals (assignment)      : ; Expression Separator
::
:: Operations are left-to-right, except for '$ &' which are right associative.
:: '<>^&' must be wrapped in double-quotes. If needed, # can always replace =.
::
:: Operands may be digits and/or variables and expressions can be of any size.
:: Result of the operation is always returned in the user variable {math}.
:: Up to 32 return variables may be assigned (eg. var1=var2=x*y+(var3=z-1)).
::
:: ECHO[n] may be used as a returnVariable to echo result with [n] line feeds.
:: {math*} and {_math*} are reserved variable names and should not be used.
::
:: ------  Many standard functions are available for use in expressions  ------
::
::               abs(num) returns the absolute value of num
::  avg(num1,num2[,numX]) returns the average value of a given list of values
::              ceil(num) returns the nearest integer not less than num
::         dim(num1,num2) returns the positive difference between num1 and num2
::           e(#decimals) returns the constant 'e' to given number of decimals
::              fact(num) returns the factorial of int(num)
::             floor(num) returns the nearest integer not greater than num
::         gcd(num1,num2) returns the greatest common divisor of two values
::  if(cond,true[,false]) returns {true} if cond <> 0, {false} or 0 if cond = 0
::               int(num) returns the nearest integer with magnitude <= num
::         lcm(num1,num2) returns the least common multiple of two values
::  max(num1,num2[,numX]) returns the largest of the given list of values
::  min(num1,num2[,numX]) returns the smallest of the given list of values
::          nth(base,exp) returns the exp-th root of the given base value
::          pi(#decimals) returns the constant 'pi' to given number of decimals
::          pow(base,exp) returns the given base raised to the power of exp
::              sign(num) returns 1 if num > 0, 0 if num = 0, or -1 if num < 0
::
:: The left parenthesis is part of the function name, no white-space is allowed.
:: Functions may have an unlimited number of parameters and are easily mod-able,
:: simply follow the pattern in the script and add the name to the function list.
::
:: -----  If operation is successful the following ErrorLevel is returned  -----
::  -1 Negative\LessThan   : 0 Zero\EqualTo\False : 1 Positive\GreaterThan\True
::
:: ----  If operation is unsuccessful the following ErrorLevel is returned  ----
::  2 Non-numeric operand  :  3 Missing operand         : 4 Missing operator
::  5 Unsupported operator :  6 Unbalanced parenthesis  : 7 Divide by zero error
::  8 Non-integer radical  :  9 Negative root undefined : 10 Function parameter
:: 11 Assignment error     : 12 Negative factorial
::
:: ---  Environment Variables shown with /Command Switch and Default Values  ---
::  _MATH_ABSOLUTE_VALUE /A0 0=respect negative input, 1=all input is positive
::     _MATH_MAX_DECIMAL /D9 9=maximum number of decimal places to return
::   _MATH_MODULUS_UNARY /M0 0=dividend, 1=divisor, 2=always positive
::     _MATH_ROUND_UP_ON /R5 5=round up on this value or greater, 0=truncate
::     _MATH_SHOW_RESULT /S0 0=never, 1=if no assignment, 2=expression, 3=both
::      _MATH_SHOW_UNARY /U0 0=negative only, 1=both, 2=none (absolute value)
::
::      /?, /H, or a lack of math expression will display this help screen.
::
:: If numbers are small enough SET /A is used for fast decimal arithmetic. The
:: script keeps track of decimal and unary adding them back to the result, but
:: when adding 9+, dividing by 9+, subtracting 10+, or multiplying by 10+ digits
:: batch routines and recursive calls are used, which are exponentially slower.
::
:: Examples:
:: math.cmd /d15 echo = 245850922 / 78256779
:: Returns '3.141592653589793' in variable {math} + echo to the screen (no LF).
::
:: math.cmd result=a1+100/(b1-4)*3
:: Parses {a1} + ((100 / ({b1} - 4)) * 3) and places answer in {result}.
:: Variable assignments must always begin a block (eg. after left parenthesis).
::
:: math.cmd /d256 /r0 /a1 echo1=answer=myVarName
:: Returns the absolute value in {myVarName} truncated to 256 decimals using
:: variable {answer} and echos the value (1 LF). 32 return variables are allowed.
::
:: math.cmd "a1=avg(n1,n2,n3,n4); a2=avg(n5,n6,n7,n8); highAvg=if(a1 > a2,a1,a2)"
:: Returns the average of the two lists in {a1} and {a2} and returns the greater
:: of the two averages in {highAvg}. Note the quotes are required for '<>^&'.
::
:: math.cmd "value1 >= value2" && GOTO :false || GOTO :true
:: Returns ERRORLEVEL=1 if true, 0 if false. Provides a full range of comparison
:: operators and can evaluate numbers of virtually any size (large or small).
::
:: math.cmd guess = (((root - 1) * guess) + (base / (guess $ (root - 1)))) / root
:: Computes the {root} of {base} number through convergence starting at {guess}.
:: Run in a loop, gets more accurate each time. Very slow, start with best guess.
::
:: math.cmd v0.2 2017/09/21 written by CirothUngol.
:: Inspired by Brian Williams' Big Math batch utilities.
:: http://www.robvanderwoude.com/battech_math.php
::
:: v0.2 2017/09/21
::      Replaced functions for removing leading and trailing zeros with macros.
::      Replaced all error GOTOs and exit GOTOs with macros.
::      Added ';' as an expression separator, now supports multiple expressions.
::      Changed SHOW_RESULT to display only if no assignment, emulates SET /A.
::      Increased number of allowed return variables from 9 to 32.
::      Fixed macros to load correctly before or after the SETLOCAL.
::
:: v0.1 2017/09/15
::      Initial release on DOStips.
Attachments
math_v02.zip
math.cmd v0.2 2017/09/21
(20.06 KiB) Downloaded 454 times
math.zip
math.cmd v0.1 2017/09/15
(19.27 KiB) Downloaded 434 times
Last edited by CirothUngol on 21 Sep 2017 23:36, edited 2 times in total.

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#2 Post by aGerman » 16 Sep 2017 04:39

CirothUngol wrote:zipped file is below

:? Nope :mrgreen:

Steffen

CirothUngol
Posts: 46
Joined: 13 Sep 2017 18:37

Re: math.cmd: a math expression parser written in native WinNT batch script

#3 Post by CirothUngol » 16 Sep 2017 11:23

Oops again... don't know what happened, probably shouldn't post stuff at 3am. ^_^

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#4 Post by aGerman » 16 Sep 2017 14:14

Great :D

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#5 Post by aGerman » 18 Sep 2017 15:57

Your script might be applicable in a forum question, see
viewtopic.php?f=3&t=8134
I wasnt't able to figure out if you implemented a separator for different assignments as the comma in SET /A

Code: Select all

set /a "x=1+2,y=3+4"
I used the # which is an equivalent of = as you wrote in your help text. It doesn't cause an error message but I assume some kind of assignment operation will be performed which is useless in that case. Did you implement any separator that should have been used instead?

Steffen

CirothUngol
Posts: 46
Joined: 13 Sep 2017 18:37

Re: math.cmd: a math expression parser written in native WinNT batch script

#6 Post by CirothUngol » 19 Sep 2017 01:18

The assignment is legal if it's at the beginning of a clause, ie. following a comma or left parenthesis:

CALL :math 32 * (xx=V1-V2)
This would put the value of V1 - V2 in variable xx (and the final result into variable math, always). You could assign several operations in this way, as long as the syntax was correct, the comma is only used in functions:

CALL :math val1=val2=fnc(n1, x=n2+1, n3*(y=n4-1))
This returns x=n2 + 1 and y=n4 - 1 as well as the entire result in val1, val2, and math. If not calling a function, just make sure the syntax is correct:

CALL :math result=echo1=(x=1+2) + (y=3+4) + (z=5*6)
This will return x=3, y=7, z=30, math=40, result=40, and echo '40' to the console (1 LF). Up to 9 variables may be returned this way (not counting 'ECHO').

As for the equals sign, the script first subs "\" for "/", then "=*^" for "#\$" just to make the string stuff easier. All of those should work as input as well as "<>&" if they're escaped or quoted as needed. Too much trouble for "==" though, you have to use "##".

I've actually rid the script of all but the basic CALL functions and all GOTOs (except for the jump to Help Screens) by installing some short macros. Still spends most of it's time in loops, so the speed increase is minimal, but I'm currently attempting to move all basic operations into macros (+-*/). That may actually alleviate the need to make any calls at all... maybe. ^_^

Thanks for the link, I'll be sure to have a look.

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#7 Post by aGerman » 19 Sep 2017 01:48

I think I pretty much understood how your script works. My point was a little different though. Meanwhile you answered in the linked thread and proposed to use a comparision operator. So that actually answers my question. Currently there is no operator that just separates different calculations without having any real operation (like comparison) in place.

Steffen

CirothUngol
Posts: 46
Joined: 13 Sep 2017 18:37

Re: math.cmd: a math expression parser written in native WinNT batch script

#8 Post by CirothUngol » 19 Sep 2017 06:35

Yes. Sorry, I should have looked at the other thread first.
Didn't really think about using a separator for multiple expressions (like in SET), but that's a good idea. How about a semi-colon ';' ? That should be easy to implement.

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#9 Post by aGerman » 19 Sep 2017 10:52

It's your decision. I'm okay with comma, semi-colon, colon ... whatever you think to be suitable :wink:

Steffen

Sponge Belly
Posts: 216
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

Re: math.cmd: a math expression parser written in native WinNT batch script

#10 Post by Sponge Belly » 20 Sep 2017 15:03

Hi CirothUngol! :)

Are you aware of Judago’s str_math.bat script?

- SB

CirothUngol
Posts: 46
Joined: 13 Sep 2017 18:37

Re: math.cmd: a math expression parser written in native WinNT batch script

#11 Post by CirothUngol » 21 Sep 2017 09:09

No, I was not! I got the seed of this idea from Brian Williams big math batch utilities. Before getting involved in it, I did search for an equivalent online but never found one.
I'm most interested in taking a look at his batch script just to see how we have done things differently (or the same), but the link you provided only mentions an update to the script and the link to the script on that page leads to nowhere ( at least it goes to nowhere when I tap with my phone). Any idea where the updated script might be?

Thanks for the info, and I hope to get a chance to take a look at it.

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#12 Post by Compo » 21 Sep 2017 09:32

Version 2.1 from December 2016!

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#13 Post by Squashman » 21 Sep 2017 10:27

CirothUngol wrote:I got the seed of this idea from Brian Williams

Didn't know he was a batch guy.
Image

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#14 Post by Squashman » 21 Sep 2017 10:31

Judago used to have his math scripts split up into each operator. I use his division.bat. His code is not limited to the 32bit maximum and it will also do floating point math.

Here was another thread about using division.
viewtopic.php?f=3&t=3854

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

Re: math.cmd: a math expression parser written in native WinNT batch script

#15 Post by Aacini » 21 Sep 2017 11:51

Perhaps you may be interested in this topic and also in this one...

Antonio

Post Reply