Page 2 of 4
Re: Fastest sen(x) in dos batch
Posted: 11 Sep 2013 09:52
by einstein1969
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
Re: Fastest sin(x) in dos batch
Posted: 16 Sep 2013 10:38
by einstein1969
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 EnableDelayedExpansion
if "%~1"=="" (set angle=300000) else set "angle=%~1"
call :INT_SinD_CosD %angle% sin cos
echo(
echo Angle:(%angle%/10000^)° Integer raw result sin=!sin! cos=!cos! & Rem Use Ansi, chcp 1252
rem pad
call :pad_sin_cos sin & call :pad_sin_cos cos
echo(
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)/100
goto :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=8660254
Pad: sin=0.5000000 cos=0.8660254
Einstein1969
Re: Fastest sin(x) in dos batch
Posted: 16 Sep 2013 12:42
by aGerman
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 conditionRegards
aGerman
Re: Fastest sin(x) in dos batch
Posted: 16 Sep 2013 13:16
by Aacini
... or this one:
The ultimate While loopAntonio
Re: Fastest sin(x) in dos batch
Posted: 16 Sep 2013 15:25
by penpen
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 off
cls
setlocal disableDelayedExpansion
call :initMacros
set "N=9"
%$example% N 4 result
:endMacro
echo %N%, 4 %result%
echo =======================
set "N=8"
%$example% N 4
:endMacro
endlocal
goto :eof
:initMacros
set LF=^
::Above 2 blank lines are required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
:::: StrLen pResult pString
set $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
Re: Fastest sin(x) in dos batch
Posted: 17 Sep 2013 07:07
by aGerman
You can't break a FOR /L loop via GOTO. You'll see that with ECHO ON
Code: Select all
@prompt $g &setlocal
set "N=10"
for /l %%i in (1 1 %N%) do (
if %%i==5 goto exitLoop
echo %%i
)
:exitLoop
pause
It executes the ECHO command only for the first 4 iterations but it doesn't stop the loop.
Regards
aGerman
Re: Fastest sin(x) in dos batch
Posted: 17 Sep 2013 09:38
by penpen
Why not? I always have seen this that way:
Code: Select all
@echo off &setlocal
set "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.
Re: Fastest sin(x) in dos batch
Posted: 17 Sep 2013 10:44
by penpen
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 off
setlocal
set "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 enableDelayedExpansion
set "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
)
)
:exitLoop
endlcoal
endlocal
goto :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
Re: Fastest sin(x) in dos batch
Posted: 27 Apr 2014 12:58
by einstein1969
@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
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 08:19
by einstein1969
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
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 11:38
by foxidrive
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.
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 12:28
by einstein1969
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 off
setlocal DisableDelayedExpansion
Echo 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.txt
setlocal 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 OFF
goto :eof
On my PC this use 143 Microseseconds.
Last code:
Code: Select all
@echo off
setlocal DisableDelayedExpansion
Echo 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.txt
setlocal 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 OFF
goto :eof
On my PC this use 95Microseseconds.
Einstein1969
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 13:21
by einstein1969
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
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 13:59
by foxidrive
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.
Re: Fastest sin(x) in dos batch
Posted: 14 Mar 2016 14:43
by einstein1969
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!