## Fastest sin(x) in dos batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

### Re: Fastest sen(x) in dos batch

Thanks Aacini, you reminded me of the old days.

In my career I have used the old turbo pascal 3.0 and I developed these things in assembler 8088 but I had forgotten that I did ...

However, I was interested to see how many digits you can get the 32bit integer math. In fact in my function INT_sin I arrived at this time to handle 5 digit without having to use too many tricks. To make a complete automatism should handle exceptions for those calculations that exceed the 32-bit and I think there is a thread where it was discussed.

But there are also differences between xp and win 7.

In my function I implemented the shift with the division . and I use it with care. I'd like to calculate the error committed in the operations in order to choose the best order in which to run. Thank you again!

Francesco aka Einstein1969

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

### Re: Fastest sin(x) in dos batch

For test the Int_sinD i had to compare result with a solid version of sin(x). Is born a new function that is a hibryd for table lookup and other trick.

This calculates sine and cosine together!

This is a function that use about 28bit at the moment to achieve 7 decimal of precision in output (0.0000001) and input in 100*microDegree (0.0001)

There is optimization that i can do for faster execution?

How can break the for loop in safe mode for use in a macro?

Code: Select all

``@echo off & setlocal EnableDelayedExpansionif "%~1"=="" (set angle=300000) else set "angle=%~1"call :INT_SinD_CosD %angle% sin cosecho(echo Angle:(%angle%/10000^)° Integer raw result sin=!sin! cos=!cos! & Rem Use Ansi, chcp 1252rem padcall :pad_sin_cos sin & call :pad_sin_cos cosecho(echo Pad: sin=!sin! cos=!cos! goto :eof:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::INT_SinD_CosD  Angle  SinResultVAR  CosResultVAR::::      -- Return the sine and cosine for the specified angle in 100*micro-degrees.::         ie. 10000 is one degree.::::         Call :INT_sinD_CosD Angle sin cos::            ::      -- Angle    [in]   in 100 micro-Degree is an integer in [-449999,449999]::::      -- SinResultVAR    [out]   var reference to return value of sine [-10000000,10000000]::::      -- CosResultVAR    [out]   var reference to return value of cosine [-10000000,10000000]::::::  Version history:::: 0.1   16/9/2013   ::::         First version Beta! Internal 27bit used::::         From Francesco Poscetti aka Einstein1969::::         NOTE: This Function allow you to calculate almost all other common::         trigonometric function. Uses the CORDIC modified algorithm.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::SetLocal EnableDelayedExpansion   set /a "a=%~1"   if %a% lss -449999 echo Not implemented. Exit. & goto :eof   if %a% gtr  449999 echo Not implemented. Exit. & goto :eof   set /a size=-1   For %%a in (450000000 265650512 140362435 71250163 35763344 17899106   8951737 4476142 2238105 1119057 559529 279765 139882 69941 34971 17485   8743 4371 2186 1093 546 273 137 68 34 17 9 4 2 1) do (set /a "size+=1" & set "at!size!=%%a")   if %a% geq 0 (     set /a x=607252935, angle=!a!*10*10*10, angle-=!at0!, y=x               ) else set /a x=607252935, angle=!a!*10*10*10, angle+=!at0!, y=-x   For /L %%# in (1,1,!size!) do (     if !angle! lss 0        (set /a "angle+=!at%%#!, dx=x/(1<<%%#), x+=y/(1<<%%#), y-=dx"     ) else if !angle! gtr 0 (set /a "angle-=!at%%#!, dx=x/(1<<%%#), x-=y/(1<<%%#), y+=dx")    )endlocal & set /a %2=(%y%+55)/100, %3=(%x%+55)/100goto :eof:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::pad_sin_cos num  setlocal EnableDelayedExpansion    if !%1! lss 0 (set "sign=-" & set /a ris=-%1) else (set "sign=" & set /a ris=%1)    set ris=0000000%ris%    set ris=!ris:~-8!    if "!ris:~0,1!" == "1" (set ris=%sign%1.%ris:~-7%) else (set ris=%sign%0.%ris:~-7%)  endlocal & set %1=%ris%goto :eof``

Output:

Code: Select all

``Angle:(300000/10000)° Integer raw result sin=5000000 cos=8660254Pad: sin=0.5000000 cos=0.8660254``

Einstein1969

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

### Re: Fastest sin(x) in dos batch

How can break the for loop in safe mode for use in a macro?

Er ... you want to break the FOR /L loop?
That's not so easy -
infinite loop with break condition

Regards
aGerman

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

### Re: Fastest sin(x) in dos batch

... or this one: The ultimate While loop

Antonio

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

### Re: Fastest sin(x) in dos batch

Another option is the following, but you have to add a label (:endMacro) after any macro call (should be no problem):

Code: Select all

``@echo offclssetlocal disableDelayedExpansioncall :initMacrosset "N=9"%\$example% N 4 result:endMacroecho %N%, 4 %result%echo =======================set "N=8"%\$example% N 4:endMacroendlocalgoto :eof:initMacrosset LF=^::Above 2 blank lines are required - do not removeset ^"\n=^^^%LF%%LF%^%LF%%LF%^^":::: StrLen pResult pStringset \$example=for /L %%n in (1 1 2) do if %%n==2 (%\n%    for /F "tokens=1-3 delims=, " %%1 in ("!argv!") do (%\n%        set "param1=!%%~1!"%\n%        set "param2=%%~2"%\n%        set "result=0"%\n%        set "N=!param1!"%\n%        for /L %%a in (1,1,!N!) do (%\n%            if !N! GEQ %%a (%\n%                set /A "N-=1", "result+=N"%\n%                echo %%%%a="%%a", N="!N!"%\n%            ) else (%\n%                echo ended N loop%\n%                echo do something after the loop%\n%                for %%v in (!result!) do endlocal^&(if "%%~3" neq "" (set "%%~3=%%v") else (echo %%v))^&goto :endMacro%\n%            )%\n%        )%\n%        for %%v in (!result!) do endlocal^&(if "%%~3" neq "" (set "%%~3=%%v") else (echo %%v))^&goto :endMacro%\n%    ) %\n%) ELSE setlocal enableDelayedExpansion ^& set argv=,exit /b``
The above places the code to execute after the condition in an else case of this condition within the loop you don't want to execute fully.
This can be done multiple times, if you are finished with what you wanted to do, just jump to a label outside the macro using goto.
In case the loop isn't executed you have to add the finishing line to all macro ending possibilities.

penpen

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

### Re: Fastest sin(x) in dos batch

You can't break a FOR /L loop via GOTO. You'll see that with ECHO ON

Code: Select all

``@prompt \$g &setlocalset "N=10"for /l %%i in (1 1 %N%) do (  if %%i==5 goto exitLoop  echo %%i):exitLooppause``

It executes the ECHO command only for the first 4 iterations but it doesn't stop the loop.

Regards
aGerman

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

### Re: Fastest sin(x) in dos batch

Why not? I always have seen this that way:

Code: Select all

``@echo off &setlocalset "N=10"for /l %%i in (1 1 %N%) do (:exitLoop  if %%i==5 goto exitLoop  echo %%i)pause``
The goto breaks the loop as it doesn't execute the loops content.
The command line interpreter just have to read the virtual document, that is inserted into the batch file by the for loop.
This is done line by line (or loop body by loop body, default) to not oversee any label.
The label cannot be found within the virtual document, as it is removed on the loop body (on normalization) when building the virtual document, so it doesn't find them within the loop.
But it doesn't execute the code, and goes to the next wanted label, so it is working.
Execution is stopped, that's what is wanted.
You should carefully select the number of iterations, as this extends the virtual document.
So do not insert a document of infinite length, the result were far from beeing optimal.

Edited:
I would agree to you if you meant this: the command line processor doesn't ignore this virtual document, although that should be not difficult to implement (and is done in all other for loops).
Then you would mean the outer script loop that implements the script loop: This loop is indeed not interrupted.

penpen

Edit2: Repositioned the text.
Last edited by penpen on 17 Sep 2013 10:49, edited 2 times in total.

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

### Re: Fastest sin(x) in dos batch

But you are right aGerman... my above code is not really good... .
As only a very small loop with maximum of 30 iterations is needed, if i see it right,
you may also do it this, more safe, way:

Code: Select all

``@echo offsetlocalset "loop=  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30"setlocal enableDelayedExpansionset "size=15"set /A "loopSize=size*3"for /F "tokens=* delims=" %%A in ("!loopSize!") do (   set "looping=!loop:~0,%%A!"   for %%a in (!looping!) do (      if %%a == 5 goto :exitLoop      echo %%a   )):exitLoopendlcoalendlocalgoto :eof``
And if you want the macro to compute on just use if else cases as in the above for /L loop scenario, and additionally with goto :endMacro use as above.

penpen

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

### Re: Fastest sin(x) in dos batch

@penpen:

Thanks penpen,

This work for small loop, i will use if there is necessity!!!
I think that work on nearly ieee 754 if optimized for performance is very good for extending math of dos batch.

@ALL:
Hi, I have rewritten the Maclaurin serie for the Sin(x) function for RADIANT angle because this is more flessible in accord with the wikipedia (english) article.

I have optimized the first, second, and third term. An this is a small library pretty fast.

I know that accessing at lookup table i more fast but in certain cases this method is more fast. Look at pgen demo for an example. The alternative is using a lookup table accessing from file but is not pretty fast how SET /A method.

I ask at experts: Am I right? There'is a faster method?

Code: Select all

``::::::::::::::::::::::::::::::::::: TRIGONOMETRIC FUNCTIONS:: call this function the first time for define some variable: PI=31416, PI_div_2=15708, PIx2=62832, PI32=3/2PI=PI+PI_div_2=47124:Init_Trig   set /a "PI=(35500000/113+5)/10, PI_div_2=(35500000/113/2+5)/10, PIx2=2*PI, PI32=PI+PI_div_2"  set "SIN=(a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000)"goto :eof:Sin rad*10000 return_var*10000 RADIANT  setlocal    set /a "a=(%1) %% %PIx2%, b=(a>>31|1)*a"    if !b! gtr %PI32% (set /a "a=a-(a>>31|1)*%PIx2%, a=%SIN%")  else (      if !b! gtr %PI_div_2% (set /a "a=(a>>31|1)*%PI%-a, a=%SIN%") else set /a "a=%SIN%")   (endlocal & set %2=%a%)goto :eof:Cos rad*10000 return_var*10000 RADIANT      Cos(x)=Sin(PI/2-x)  setlocal    set /a "a=(%PI_div_2%-%1) %% %PIx2%, b=(a>>31|1)*a"    if !b! gtr %PI32% (set /a "a=a-(a>>31|1)*%PIx2%, a=%SIN%")  else (      if !b! gtr %PI_div_2% (set /a "a=(a>>31|1)*%PI%-a, a=%SIN%") else set /a "a=%SIN%")   (endlocal & set %2=%a%)goto :eof::::::::::::::::::::::::::::::::::: TRIGONOMETRIC FUNCTIONS END``

einstein1969

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

### Re: Fastest sin(x) in dos batch

Hi,

The faster method developed by Aacini is this:
This version is about EDIT:40% faster (101microseconds in empty env) than previuos.

Code: Select all

``  set "_SIN=a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000"  REM APA mod  REM http://www.dostips.com/forum/viewtopic.php?f=3&t=6744  REM                                  if !c! gtr 47124   (set /a "a=a-(a>>31|1)*62832") else if !c! gtr 15708  set /a "a=(a>>31|1)*31416-a"  set "SIN(x)=(a=(x)%%62832, c=(a>>31|1)*a, t=((c-47125)>>31)+1, a-=t*((a>>31|1)*62832)  +  ^^^!t*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a)  ), %_SIN%)"  set "_SIN="``

Usage:

Code: Select all

``  set /A "sx=%SIN(x):x=45*31416/180%"``

I found alternative at !t that is (1-t) and I have not precalculate t but substitute directly.
This version is about 6% faster (95microseconds in empty env!!) than previous.

Code: Select all

``  set "SIN(x)=(a=(x)%%62832, c=(a>>31|1)*a, a-=(((c-47125)>>31)+1)*((a>>31|1)*62832)  +  (-((c-47125)>>31))*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a)  ), %_SIN%)"``

The timing is calculated on old Celeron@2Ghz

Einstein1969
Last edited by einstein1969 on 14 Mar 2016 14:37, edited 2 times in total.

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

### Re: Fastest sin(x) in dos batch

einstein, can you supply a batch script to test the relative speeds of the two routines, over a set of caluclations?

My thoughts are that I'd be interested to see how a later model PC will render the two routines, compared to your monocore 2 GHz Celeron.

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

### Re: Fastest sin(x) in dos batch

I use this.
The result is on EDIT:screen. Close any application for stabilize. I don't know if on multicore this is necessary.

Let me know if it works.

For old version:

Code: Select all

``@echo offsetlocal DisableDelayedExpansionEcho Close any application, browser, and suspend process that use CPU.Echo You can use Resource Monitor under Task Manager , select a process and right click to suspend.Echo Close Task Manager and Resource Monitor.Pause set FPS=if   %%\ geq !\!  (set "FPS_t1=1!time:~-5,-3!!time:~-2!" ^& ((set /p "FPS_old_counter=" ^& set /p "FPS_t0=")^<%tmp%\FPS.\$\$\$.dat.txt) ^& set /a "FPS_dt=FPS_t1-FPS_t0, FPS_check=FPS_dt-1>>31, FPS_rapp=FPS_dt/(FPS_dt+(FPS_check&1)), FPS=(%%\-FPS_old_counter)*10000*100/(FPS_dt+(FPS_check&6000)), \=%%\+6*FPS/100/100+(1-FPS_rapp)*100, FPS_micro=1000000000/(FPS+(FPS-1>>31&1))" ^& Echo FPS=!FPS:~0,-2!.!FPS:~-2! [!FPS_micro:~0,-1!.!FPS_micro:~-1! æs] [#%%\-!\!] ^&set FPS_t1=^&set FPS_old_counter=^&set FPS_t0=^&set FPS_dt=^&set FPS_check=^&set FPS_rapp=^&set FPS=^&set FPS_micro=^& ( (echo %%\)^>%tmp%\FPS.\$\$\$.dat.txt ^& (echo 1!time:~-5,-3!!time:~-2!)^>^>%tmp%\FPS.\$\$\$.dat.txt) )set INIT_FPS=set \=0^&(echo 0^&echo 1%time:~-5,-3%%time:~-2%)^>%tmp%\FPS.\$\$\$.dat.txtsetlocal EnableDelayedExpansion%= Put here definition of macro or initialize value =%  set /a "PI=(35500000/113+5)/10, PI_div_2=(35500000/113/2+5)/10, PIx2=2*PI, PI32=PI+PI_div_2"  set "SIN=(a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000)"::BURST MODE ON(setlocal & for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="  rem preallocate env. sometimes it works sometimes not. Remove rem for try.   rem (for /L %%\ in (1,1,2000) do (set z=!z!0000&set z1=!z1!0000)) & set z=&set z1=  (%INIT_FPS%)For /L %%\ in (1,1,1600000) do (( For /L %%? in (0,1,99) do (%= Insert here the code to timing =%    set /a "a=(45*31416/180) %% %PIx2%, b=(a>>31|1)*a"    if !b! gtr %PI32% (set /a "a=a-(a>>31|1)*%PIx2%, a=%SIN%")  else (      if !b! gtr %PI_div_2% (set /a "a=(a>>31|1)*%PI%-a, a=%SIN%") else set /a "a=%SIN%")    set /A sx=a  ))  %FPS%)endlocal)::BURST MODE OFFgoto :eof``

On my PC this use 143 Microseseconds.

Last code:

Code: Select all

``@echo offsetlocal DisableDelayedExpansionEcho Close any application, browser, and suspend process that use CPU.Echo You can use Resource Monitor under Task Manager , select a process and right click to suspend.Echo Close Task Manager and Resource Monitor.Pause set FPS=if   %%\ geq !\!  (set "FPS_t1=1!time:~-5,-3!!time:~-2!" ^& ((set /p "FPS_old_counter=" ^& set /p "FPS_t0=")^<%tmp%\FPS.\$\$\$.dat.txt) ^& set /a "FPS_dt=FPS_t1-FPS_t0, FPS_check=FPS_dt-1>>31, FPS_rapp=FPS_dt/(FPS_dt+(FPS_check&1)), FPS=(%%\-FPS_old_counter)*10000*100/(FPS_dt+(FPS_check&6000)), \=%%\+6*FPS/100/100+(1-FPS_rapp)*100, FPS_micro=1000000000/(FPS+(FPS-1>>31&1))" ^& Echo FPS=!FPS:~0,-2!.!FPS:~-2! [!FPS_micro:~0,-1!.!FPS_micro:~-1! æs] [#%%\-!\!] ^&set FPS_t1=^&set FPS_old_counter=^&set FPS_t0=^&set FPS_dt=^&set FPS_check=^&set FPS_rapp=^&set FPS=^&set FPS_micro=^& ( (echo %%\)^>%tmp%\FPS.\$\$\$.dat.txt ^& (echo 1!time:~-5,-3!!time:~-2!)^>^>%tmp%\FPS.\$\$\$.dat.txt) )set INIT_FPS=set \=0^&(echo 0^&echo 1%time:~-5,-3%%time:~-2%)^>%tmp%\FPS.\$\$\$.dat.txtsetlocal EnableDelayedExpansion%= Put here definition of macro or initialize value =%  set "_SIN=a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000"  REM APA mod: Convert final sine calculation into a long "function" expression  REM http://www.dostips.com/forum/viewtopic.php?f=3&t=6744  REM                                  if !c! gtr 47124   (set /a "a=a-(a>>31|1)*62832") else if !c! gtr 15708  set /a "a=(a>>31|1)*31416-a"  set "SIN(x)=(a=(x)%%62832, c=(a>>31|1)*a, a-=(((c-47125)>>31)+1)*((a>>31|1)*62832)  +  (-((c-47125)>>31))*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a)  ), %_SIN%)"  set "_SIN="::BURST MODE ON(setlocal & for /F "Tokens=1 delims==" %%v in ('set') do set "%%v="  rem preallocate env. sometimes it works sometimes not. Remove rem for try.   rem (for /L %%\ in (1,1,2000) do (set z=!z!0000&set z1=!z1!0000)) & set z=&set z1=  (%INIT_FPS%)For /L %%\ in (1,1,1600000) do (( For /L %%? in (0,1,99) do (%= Insert here the code to timing =%  set /A "sx=%SIN(x):x=45*31416/180%"  ))  %FPS%)endlocal)::BURST MODE OFFgoto :eof``

On my PC this use 95Microseseconds.

Einstein1969
Last edited by einstein1969 on 21 Mar 2016 07:54, edited 2 times in total.

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

### Re: Fastest sin(x) in dos batch

For better result i use often the 10X instruction like this:

Code: Select all

``...%= Insert here the code to timing =%  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"  set /A "sx=%SIN(x):x=45*31416/180%"...  ``

And divide by 10 the result.

Einstein1969
Last edited by einstein1969 on 14 Mar 2016 14:20, edited 1 time in total.

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

### Re: Fastest sin(x) in dos batch

I assume it runs continuously so I copied a few lines - this is the result from the first and second scripts.

Code: Select all

``FPS=19189.62 [52.1 µs] [#1485-2636]FPS=19312.08 [51.7 µs] [#2636-3794]FPS=19332.22 [51.7 µs] [#3794-4953]``

Code: Select all

``FPS=2004.04 [498.9 µs] [#100-220]FPS=1948.05 [513.3 µs] [#220-336]FPS=1979.52 [505.1 µs] [#336-454]``

It doesn't run both sin methods to compare them, does it?
Too early in the morning for me to follow it all. einstein1969
Expert
Posts: 776
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: Fastest sin(x) in dos batch

I have editated the previous posts (last 3). I have correct a value. The performance gain is about 40% with the Aacini version
and total 45% for the last.

Einstein1969

EDIT: Your PC is 2 times fast than mine! on single core!