Dos Batch Math Library

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

Dos Batch Math Library

#1 Post by einstein1969 » 08 Aug 2014 03:00

Hi to all,

on the main site lack the mathematical functions.

Since many user here, and elsewhere on the web, they have developed a lot, you can now reap the fruits of their sowing and planting new seeds.

I hope for the cooperation of all to make a point of reference.

I have not tried on StackOverflow/Stack... nor groups discussion or sites, for example, in German (or Russian or other) because they do not know the German nor the Russian enough. So if someone speaking German or Russian or else can do a search and also bring only the link where they talk about mathematical functions I will take the responsibility to keep this thread neat.

I had thought to create functions that could go well for both 32bit integers, 64bit integer (2*32), a fixed point math as simple as that defined by Antonio Acini, the float point defined by Penpen, I thought I'd define a new mathematical fixed point such as the one defined in the console games (for example see Nintendo DS).

I also decided to make versions that take advantage of the concept of macro.


List functions to implement:

  • Abs(x)
  • Sign(x)
  • Ceil(x)
  • Floor(x)
  • Cos(x)
  • Sin(x)
  • Tan(x)
  • Pow(x,y)
  • Log(x)
  • Ln(x)
  • Round(x)
  • Sqrt(x)
  • Hypot(x,y)
  • Min(x,y)
  • Max(x,y)
  • Cmp(x,y)


Reference:
(nearly) ieee 754 floating point single precisition by penpen
Definition and use of arithmetic "functions" in Batch files by Antonio Acini aka Aacini


Thanks to all
Francesco Poscetti aka einstein1969
Last edited by einstein1969 on 24 Nov 2015 17:45, edited 5 times in total.

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

Re: Dos Batch Math Library

#2 Post by einstein1969 » 08 Aug 2014 03:13

Example of implementations of abs(x):

Suppose that the x is 32bit signed INTEGER.

  1. Code: Select all

    Set /a X=-56789
    if %X% lss 0 set /a X=-X

  2. Code: Select all

    set /a "x=-56789,  x=(x>>31|1)*x"
...

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

Re: Dos Batch Math Library

#3 Post by einstein1969 » 08 Aug 2014 03:15

  • Abs(x)

    Code: Select all

    set "Abs(x)=(((x)>>31|1)*(x))"
    set /A "x=-32, abs=%Abs(x)%"
    rem or
    set /A Abs=%Abs(x):x=-32%
  • Sign(x)

    Code: Select all

    set "Sign(x)=(x)>>31 | -(x)>>31 & 1" 
    :: or
    set "Sign(x)=(x)>>31 | -(-(x)>>31)"
    ::
    set /A "x=-32, S=%Sign(x)%"
    set /A "S=%Sign(x):x=-32%"
  • Ceil(x)
  • Floor(x)
  • Cos(x)
  • Sin(x)
  • Tan(x)
  • Pow(x,y)
  • Log(x)
  • Ln(x)
  • Round(x)
  • Sqrt(N)

    Code: Select all

    Rem Without exception on negative input
    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 )"
    set /A "N=36, sqrt=%Sqrt(N)%"
    rem or
    set /A "Sqrt=%Sqrt(N):N=36%"

    Rem With exception on negative input
    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)/(1+((N)>>31)) )"
    set /A "Sqrt=%Sqrt(N):N=-32%"
  • Hypot(x,y)
  • Min(x,y)
  • Max(x,y)
  • Cmp(x,y)

    Code: Select all

    set "Cmp(x,y)=(x-y)>>31|((y-x)>>31&1)"
    set /A "x=3, y=5, C=%Cmp(x,y)%"
Last edited by einstein1969 on 01 May 2016 08:32, edited 7 times in total.

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

Re: Dos Batch Math Library

#4 Post by einstein1969 » 08 Aug 2014 03:31

example of implementation of sqrt(x):

input 32 bit integer output 32bit integer

by Antonio Acini:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set /A number=%1
set /A iter1=number/2+1

rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
   set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
   if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
)
echo Sqrt(%number%) = %sqrt%

modified the first set to set /A (sugg. by dbenham)
modified the first iter1 adding + 1
Last edited by einstein1969 on 11 Aug 2014 01:13, edited 3 times in total.

dbenham
Expert
Posts: 2254
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Math Library

#5 Post by dbenham » 09 Aug 2014 14:28

For SQRT.BAT, modify initial assignment to use SET /A

Code: Select all

set /a number=%1

Then you can enter hex notation for a number, or compute the integral approximation of the square root of a mathematical expression. It is also a good way to test the result.

Code: Select all

C:\test>sqrt 23456*23456
Sqrt(550183936) = 23456

C:\test>


Dave Benham

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

Re: Dos Batch Math Library

#6 Post by einstein1969 » 09 Aug 2014 19:40

Thanks Dave.

For completeness. In the algos there is (X+Y)/2. It's the average.

This is a average without overflow:

Code: Select all

  set /a "M=(X&Y)+(X^Y)/2"


In the sqrt algos is not necessary, I think, but for other calculations:

examples:

Code: Select all

>set /a "m=(2100000001+2000000001)/2"
-97483647


Code: Select all

>set /a "m=(2100000001&2000000001)+(2100000001^2000000001)/2"
2050000001


Francesco Poscetti
Last edited by einstein1969 on 09 Aug 2014 21:13, edited 1 time in total.

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

Re: Dos Batch Math Library

#7 Post by Aacini » 09 Aug 2014 20:00

@einstein1969:

This is very interesting! Could you explain why the "(X&Y)+(X^Y)/2" give correct results with large numbers, but "(X+Y)/2" does not, perhaps?

In assembler, when you want to multiply two numbers followed by a division (for example: X*Y/Z, common operation to change scale) you may multiply X*Y, that give a result of double the size of X and Y, and then directly divide this double-size partial result by Z. If the scaling is correct, the final result is correct even if the partial result of X*Y would produce an overflow in the base size of X and Y.

Is there any way to apply your trick above to an X*Y/Z operation in a SET /A command?

Antonio

EDIT: PS - You may find some interesting stuff on mathematical functions in my SET/A macro post.

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

Re: Dos Batch Math Library

#8 Post by einstein1969 » 09 Aug 2014 21:46

I have added a decimal part (5 digit) at the Aacini's square root, using the standard algorithm of square root. (rif . Arithmetic Extraction of Square Roots)

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set /A number=%1
set /A iter1=number/2

rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
   set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
   if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
)
rem echo Sqrt(%number%) = %sqrt%

rem decimal part
set count=0
set /a sqr=sqrt*sqrt

if !sqr! gtr !number! set /a sqrt-=1, sqr=sqrt*sqrt

set digit=%sqrt%.

:dec
(   set /a count+=1
   if !count! GTR 5 goto next
   set /a number=(number-sqr^)*100, div=sqrt*2
   for /l %%i in (9,-1,0) do (
      set /a sqr=!div!%%i*%%i
      if !sqr! leq !number! (
         set sqrt=!sqrt!%%i
         goto dec
      )
   )
)   
:next   
   set sqrt=%sqrt:~-5%
   if %number% neq 0 set digit=%digit%%sqrt%
   echo Square Root of %1 is %digit%


exit /b 0

EDIT:Above code has errors

examples

Code: Select all

>sqrt.bat 2
Sqrt(2) = 1
Square Root of 2 is 1.41421


EDIT: look at SQRT.BAT for enhanced version by dbenham
Last edited by einstein1969 on 11 Aug 2014 01:30, edited 6 times in total.

dbenham
Expert
Posts: 2254
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Math Library

#9 Post by dbenham » 09 Aug 2014 22:02

Impressive. But SQRT 3 original code gives 2, and decimal version gives 2.2.

Dave Benham
Last edited by dbenham on 10 Aug 2014 03:37, edited 1 time in total.

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

Re: Dos Batch Math Library

#10 Post by einstein1969 » 09 Aug 2014 22:54

dbenham wrote:Impressive. But SQRT 2 original code gives 2, and decimal version gives 2.2.

Dave Benham


:?:

What? what do you mean?

dbenham
Expert
Posts: 2254
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Math Library

#11 Post by dbenham » 10 Aug 2014 03:38

:oops: Stoopid typos :!:

That was supposed to be a 3. I edited my post.

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

Re: Dos Batch Math Library

#12 Post by einstein1969 » 10 Aug 2014 03:58

I can't understand why... I have added a "stupid" workaround and seem work.

Code: Select all

if !sqr! gtr !number! set /a sqrt-=1, sqr=sqrt*sqrt


update the previus post.

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

Re: Dos Batch Math Library

#13 Post by einstein1969 » 10 Aug 2014 04:13

Aacini wrote:@einstein1969:

This is very interesting! Could you explain why the "(X&Y)+(X^Y)/2" give correct results with large numbers, but "(X+Y)/2" does not, perhaps?

In assembler, when you want to multiply two numbers followed by a division (for example: X*Y/Z, common operation to change scale) you may multiply X*Y, that give a result of double the size of X and Y, and then directly divide this double-size partial result by Z. If the scaling is correct, the final result is correct even if the partial result of X*Y would produce an overflow in the base size of X and Y.

Is there any way to apply your trick above to an X*Y/Z operation in a SET /A command?

Antonio

EDIT: PS - You may find some interesting stuff on mathematical functions in my SET/A macro post.


Thanks Antonio for the link. I see a lot of stuff! If possibile I integrate but your work is very advanced! :shock:

For the question. The + go in overflow. The & and ^ no. This proprierty is discoverer by Dietz.

For the MUL i think that this is not applicable. You can use KARATSUBA. I'll post an example soon.

Francesco

dbenham
Expert
Posts: 2254
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Math Library

#14 Post by dbenham » 10 Aug 2014 19:23

Your code sometimes raises errors, and the last digit is not rounded properly, and sometimes is just plain wrong.

I refined your SQRT function to compute an accurately rounded value with as much precision as possible without resorting to numbers that exceed signed 32 bit values. I also eliminated any backward GOTO for improved performance. The function properly handles negative, 0, and 1 values.

I thought I could add 5 and divide by 10 to get a properly rounded number, but the last digit was sometimes off by 1. Via some spot checking at both extremes (small numbers and big numbers), I determined that adding 50 and dividing by 100 seems to give a reliably accurate rounded value.

I tested 10001 small inputs from 0 to 1000, as well as 1000 large inputs from 2147483647 to 2146483647, incrementing by 1000.

I have not looked at Aacini's linked code to see if there are better ways to do this.

Code: Select all

@echo off

:SQRT  InExpr  [OutVar]
::
:: Compute the square root of expression InExpr
:: and store the result in variable OutVar.
:: Write the result to stdout if OutVar not specified.
::
:: InExpr may be a valid SET /A mathematical expression.
::
:: The number is rounded accurately, and the number of
:: digits varies depending on the value of InExpr.
::
:: If the result is exact, then it will not have any
:: decimal digits.
::
setlocal EnableDelayedExpansion

:: Initialize and handle special cases
set /A "number=%~1, iter1=number/2+1" || exit /b
if !number! lss 0 >&2 echo ERROR: Imaginary number&exit /b 1
if !number! leq 1 set /a sqrt=number&goto return

:: Compute integral portion
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
  set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
  if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2, sqr=sqrt*sqrt, count=0"
)
if !sqr! equ !number! goto return

:: Compute decimal portion
for /l %%N in (-1 1 6) do (
  set /a "number=(number-sqr)*100, div=sqrt*2"
  if !number! lss 0 goto finish
  set "next="
  for /l %%i in (9,-1,0) do if not defined next (
    set /a sqr=!div!%%i*%%i 2>nul || goto finish
    if !sqr! geq 0 if !sqr! leq !number! set "next=%%i"
  )
  set "sqrt=!sqrt!!next!"
  set "count=%%N"
)
:finish
set /a sqrt=(sqrt+50)/100
set sqrt=!sqrt:~0,-%count%!.!sqrt:~-%count%!

:return
endlocal & if "%~2" equ "" (echo %sqrt%) else set "%~2=%sqrt%"
exit /b 0


Dave Benham
Last edited by dbenham on 11 Aug 2014 07:02, edited 2 times in total.

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

Re: Dos Batch Math Library

#15 Post by einstein1969 » 11 Aug 2014 00:58

I have found the error in the previus method. I think this method uses this algos.

The first term is

Code: Select all

iter1=number/2+1
and not

Code: Select all

iter1=number/2
. I have probed e seem work without my previous "stupid" patch.

@Dave
You can correct previus post?

PS: Very good work!

Post Reply