## Fastest sin(x) in dos batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

### Fastest sin(x) in dos batch

hi,

I need to have the sine function in batch. Should be as fast as possible. I only need a few decimal (2-3 or 4) after the decimal point as a result or integer values ​​to be divided. In input also an integer value of degrees or cents / thousandths of degrees.

You could use the mathematics of integers of dos batch to be more 'fast?
Last edited by einstein1969 on 15 Sep 2013 09:00, edited 1 time in total.

Endoro
Posts: 244
Joined: 27 Mar 2013 01:29
Location: Bozen

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

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

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

I'm sorry, I forgot to add that I would not install anything, so if possible in pure batch dos or with what is available by default.

In that link I could find only two batch but require php.

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

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

I did a test and still does not seem to be very fast.

I cycled about 1000 times and has taken too much on my pc ..

Code: Select all

``E:\x264\provini\php>cmd /V:ON /c "echo %time% & ( for /L %# in (1,1,1000) do @(php.exe -r print(sin("3"^)^); > nul: ) ) & echo !time!"16:40:08,2316:40:39,43``

about 0.030 sec or 30 ms

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

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

Ok.

I init the skeleton

Int_Sinx:

Code: Select all

``:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::INT_Sinx  Degree  [ResultVAR]::::      -- Return the sine for the specified angle in degrees. y=sin(x), where x is in integer::      ::      -- Degree    [in]    Degree is an integer in [0,90]::::      -- ResultVAR    [out]   var reference to return value of y [0,100]::::  Version history:::: 0.1   4/9/2013   First version that use 2 decimal for result e input in integer degree::         for angle from 0 to 90 degree.::::         From Francesco Poscetti aka Einstein1969::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::SETLOCAL   REM.--function body   set /a d=%~1   if %d% lss 0 echo Not implemented. Exit. & goto :eof   if %d% gtr 90 echo Not implemented. Exit. & goto :eof   set /a y=(r=x=314*d/180)-(yp=x*x*x)/6/(o=100)/o+yp*x/120*x/o/o/o/o(ENDLOCAL & REM -- RETURN VALUES    IF "%~2" NEQ "" (SET %~2=%y%) ELSE Echo %y%)GOTO:EOF::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::``

For now only first quadrant, the other three are easy

test_code.cmd

Code: Select all

``@echo off setlocalsetlocal EnableDelayedExpansionset st=For /L %%# in (1,1,52) do call set st=#%%st%%For /L %%# in (0,4,90) do (    call :Int_Sinx %%# INT_Sinx_result   set /a "int_sinx_result>>=1"   call set st_=%%st:~0,-!int_sinx_result!%%   echo(!st_!)For /L %%# in (90,-4,0) do (    call :Int_Sinx %%# INT_Sinx_result   set /a "int_sinx_result>>=1"   call set st_=%%st:~0,-!int_sinx_result!%%   echo(!st_!)``

Result:

Code: Select all

``##########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################``

EDIT: changed for more performance

raw performance sin(45)=0.71:

Code: Select all

``E:\x264\provini>cmd /V:ON /c "echo %time% & set degree=45 & ( for /L %# in (1,1,10000) do @(set /a "y=(r=x=314*degree/180)-(p=x*x*x)/6/(o=100)/o+p*x/120*x/o/o/o/o") >nul) & echo !time! & if !y! lss 10 (echo 0.0!y!) else if !y! lss 100 (echo 0.!y!) else echo 1.00"22:49:16,8922:49:19,870.71``

3sec/10000= 0.0003s or 0.3ms

.

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

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

One quite fast solution can be read here: http://lab.polygonal.de/?p=205.
Although this is not done using integer arithmetics, but it may easily be converted to.

penpen

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

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

Thanks penpen the link is very full of trick.

I have tested the fast quadratic version but there is so much error

at 30 degrees the sin(30°)=0,5 but the fast quadratic version is 0,555...

I test quality quadratic version now!

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

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

You may think this is cheating, but it certainly is fast, accurate, and pure batch

(I did use JScript to initially get the lookup values - not shown)

It provides an accurate sin() value for any integral number of degrees, with 5 decimal digits of precision. The 5 was an arbitrary choice.

An extremely fast direct lookup is used for values between 0 and 359: 0.09 msec on my machine.

A macro is used for any other integral value: 0.81 msec on my machine

I can't figure out why the macro "call" must be within parentheses

Code: Select all

``@echo offsetlocal disableDelayedExpansion:: =========================== Begin Initialization ================================set LF=^set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"set ^"sin=%\n%for %%# in (1 2) do if %%#==2 (for /f "tokens=1,2" %%1 in ("!args!") do (%\n%  set /a "N=%%1%%360"%\n%  if !N! lss 0 set /a "N+=360"%\n%  for %%N in (!N!) do for %%n in (!sin%%N!) do (%\n%    endlocal%\n%    if "%%2" equ "" (echo %%n) else set "%%2=%%n"%\n%  )%\n%)) else setlocal enableDelayedExpansion^&set args=^"setlocal enableDelayedExpansionset N=0for %%V in (0.00000 0.01745 0.03490 0.05234 0.06976 0.08716 0.10453 0.12187 0.13917 0.156430.17365 0.19081 0.20791 0.22495 0.24192 0.25882 0.27564 0.29237 0.30902 0.325570.34202 0.35837 0.37461 0.39073 0.40674 0.42262 0.43837 0.45399 0.46947 0.484810.50000 0.51504 0.52992 0.54464 0.55919 0.57358 0.58779 0.60182 0.61566 0.629320.64279 0.65606 0.66913 0.68200 0.69466 0.70711 0.71934 0.73135 0.74314 0.754710.76604 0.77715 0.78801 0.79864 0.80902 0.81915 0.82904 0.83867 0.84805 0.857170.86603 0.87462 0.88295 0.89101 0.89879 0.90631 0.91355 0.92050 0.92718 0.933580.93969 0.94552 0.95106 0.95630 0.96126 0.96593 0.97030 0.97437 0.97815 0.981630.98481 0.98769 0.99027 0.99255 0.99452 0.99619 0.99756 0.99863 0.99939 0.999851.00000 0.99985 0.99939 0.99863 0.99756 0.99619 0.99452 0.99255 0.99027 0.987690.98481 0.98163 0.97815 0.97437 0.97030 0.96593 0.96126 0.95630 0.95106 0.945520.93969 0.93358 0.92718 0.92050 0.91355 0.90631 0.89879 0.89101 0.88295 0.874620.86603 0.85717 0.84805 0.83867 0.82904 0.81915 0.80902 0.79864 0.78801 0.777150.76604 0.75471 0.74314 0.73135 0.71934 0.70711 0.69466 0.68200 0.66913 0.656060.64279 0.62932 0.61566 0.60182 0.58779 0.57358 0.55919 0.54464 0.52992 0.515040.50000 0.48481 0.46947 0.45399 0.43837 0.42262 0.40674 0.39073 0.37461 0.358370.34202 0.32557 0.30902 0.29237 0.27564 0.25882 0.24192 0.22495 0.20791 0.190810.17365 0.15643 0.13917 0.12187 0.10453 0.08716 0.06976 0.05234 0.03490 0.017450.00000 -0.01745 -0.03490 -0.05234 -0.06976 -0.08716 -0.10453 -0.12187 -0.13917 -0.15643-0.17365 -0.19081 -0.20791 -0.22495 -0.24192 -0.25882 -0.27564 -0.29237 -0.30902 -0.32557-0.34202 -0.35837 -0.37461 -0.39073 -0.40674 -0.42262 -0.43837 -0.45399 -0.46947 -0.48481-0.50000 -0.51504 -0.52992 -0.54464 -0.55919 -0.57358 -0.58779 -0.60182 -0.61566 -0.62932-0.64279 -0.65606 -0.66913 -0.68200 -0.69466 -0.70711 -0.71934 -0.73135 -0.74314 -0.75471-0.76604 -0.77715 -0.78801 -0.79864 -0.80902 -0.81915 -0.82904 -0.83867 -0.84805 -0.85717-0.86603 -0.87462 -0.88295 -0.89101 -0.89879 -0.90631 -0.91355 -0.92050 -0.92718 -0.93358-0.93969 -0.94552 -0.95106 -0.95630 -0.96126 -0.96593 -0.97030 -0.97437 -0.97815 -0.98163-0.98481 -0.98769 -0.99027 -0.99255 -0.99452 -0.99619 -0.99756 -0.99863 -0.99939 -0.99985-1.00000 -0.99985 -0.99939 -0.99863 -0.99756 -0.99619 -0.99452 -0.99255 -0.99027 -0.98769-0.98481 -0.98163 -0.97815 -0.97437 -0.97030 -0.96593 -0.96126 -0.95630 -0.95106 -0.94552-0.93969 -0.93358 -0.92718 -0.92050 -0.91355 -0.90631 -0.89879 -0.89101 -0.88295 -0.87462-0.86603 -0.85717 -0.84805 -0.83867 -0.82904 -0.81915 -0.80902 -0.79864 -0.78801 -0.77715-0.76604 -0.75471 -0.74314 -0.73135 -0.71934 -0.70711 -0.69466 -0.68200 -0.66913 -0.65606-0.64279 -0.62932 -0.61566 -0.60182 -0.58779 -0.57358 -0.55919 -0.54464 -0.52992 -0.51504-0.50000 -0.48481 -0.46947 -0.45399 -0.43837 -0.42262 -0.40674 -0.39073 -0.37461 -0.35837-0.34202 -0.32557 -0.30902 -0.29237 -0.27564 -0.25882 -0.24192 -0.22495 -0.20791 -0.19081-0.17365 -0.15643 -0.13917 -0.12187 -0.10453 -0.08716 -0.06976 -0.05234 -0.03490 -0.01745) do (  set "sin!N!=%%V"  set /a "N+=1"):: =========================== End Initialization ================================:: Use direct lookup if angle is known to be an integer between 0 and 359 inclusivefor %%N in (0 45 90 135 180 225 270 315) do echo sin(%%N^) = !sin%%N!:: Use macro if angle may be negative or >= 360for %%N in (-45 405) do (  (%sin% %%N N)  echo sin(%%N^) = !N!)echo(echo Speed test direct lookup between 0 and 359echo %time%for /l %%N in (0 1 10000) do set "N=!sin180!"echo %time%echo(echo Speed test using macroecho %time%for /l %%N in (0 1 10000) do (%sin% %%N N)echo %time%``
=== OUTPUT ===

Code: Select all

``sin(0) = 0.00000sin(45) = 0.70711sin(90) = 1.00000sin(135) = 0.70711sin(180) = 0.00000sin(225) = -0.70711sin(270) = -1.00000sin(315) = -0.70711sin(-45) = -0.70711sin(405) = 0.70711Speed test direct lookup between 0 and 35920:02:53.1620:02:54.12Speed test using macro20:02:54.1220:03:02.22``

Dave Benham

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

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

Well what to say? it's amazing what you can do!

The use of the macro is brilliant and incomprehensible to me. The code is clearly legible and easy to use.

How can I use a macro in my function?

In the meantime, I wrote a new version that has nothing to do with the final version.

The question I asked myself when I read the link posted by penpen is just the limit of the memory space of the variables, so I discarded the version with quick lookup tables because the input function will also have tenths, hundredths and thousandths of a degree.

Thank you very much dbenham

The new version. More precise e more fast

Code: Select all

``:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::INT_SinD  Degree  [ResultVAR]::::      -- Return the sine for the specified angle in degrees. y=sin(x), where x is in integer::      ::      -- Degree    [in]    Degree is an integer in [0,90]::::      -- ResultVAR    [out]   var reference to return value of y [0,100]::::::  Version history:::: 0.2  6/9/2013   ::         1) Improved precision using sine/cosine property::         2) optimization of integer use and new formula usage::         3) changhed name for "degree" input::         4) implemented "round" function for more precision, internal work on 3 digit:::: 0.1   4/9/2013   ::         First version that use 2 decimal for result e input in integer degree::         for angle from 0 to 90 degree.::::         From Francesco Poscetti aka Einstein1969::::         This Function allow you to calculate almost all other common trigonometric ::         function. Use the Taylor/Maclaurin function.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::SETLOCAL   REM.--function body   set /a "d=%~1"   if %d% lss 0 echo Not implemented. Exit. & goto :eof   if %d% gtr 90 echo Not implemented. Exit. & goto :eof   if %d% leq 48 (      set /a "y=((x=3141592*d/180/(o=1000))-x*x*x/6/(o*o)+5)/10"   ) else (      set /a "y=((o=1000)-(x=3141592*(90-d)/180/o)*x/2/o+5)/10"   )(ENDLOCAL & REM -- RETURN VALUES    IF "%~2" NEQ "" (SET %~2=%y%) ELSE Echo %y%)GOTO:EOF::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::``

Einstein1969

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

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

How can I use a macro in my function?

Try:

Code: Select all

``@echo off &setlocalset LF=^set ^"\n=^^^%LF%%LF%^%LF%%LF%^^" &REM Two empty lines required!set sin==for %%i in (1 2) do if %%i==2 (%\n%  for /f "tokens=1,2" %%j in ("!argv!") do (set /a "d=%%~j" ^& set "ret=%%~k")%\n%  if !d! geq 0 (%\n%    if !d! leq 90 (%\n%      if !d! leq 48 (%\n%        set /a "y=((x=3141592*d/180/(o=1000))-x*x*x/6/(o*o)+5)/10"%\n%      ) else (%\n%        set /a "y=((o=1000)-(x=3141592*(90-d)/180/o)*x/2/o+5)/10"%\n%      )%\n%      for /f "tokens=1,2" %%j in ("!y! !ret!") do (%\n%        ENDLOCAL%\n%        if "%%k" NEQ "" (SET %%k=%%j) ELSE Echo %%j%\n%      )%\n%    ) else (%\n%      ENDLOCAL%\n%      echo Not implemented.%\n%    )%\n%  ) else (%\n%    ENDLOCAL%\n%    echo Not implemented.%\n%  )%\n%) else SETLOCAL EnableDelayedExpansion ^& set argv=:::::::::::::::::::::::::%sin% 0%sin% 45%sin% 90 resultecho %result%pause``

Regards
aGerman

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

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

thanks a lot, aGerman!

It seems to work fine. Can I ask why there are all those endlocal?

However, I baked the new version rather complete and running, however, still to be optimized for better performance.

Code: Select all

``:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::INT_SinD  Degree  [ResultVAR]::::      -- Return the sine for the specified angle in degrees. ::         y=INT_sinD(x), where x is in integer and y is an integer::         y is the integer (rounded) part of sine moltiply 100.::      ::      -- Degree      [in]    Degree is an integer in [-2147483647,2147483647]::::      -- ResultVAR    [out]   var reference to return value of y [-100,100]::::::  Version history:::: 0.3  7/9/2013::         1) improved precision. Error max=0.0052::         2) implemented for range in [-2147483647,2147483647] , return [-100,100]:::: 0.2  6/9/2013   ::         1) Improved precision using sine/cosine property Sin(x)=...::         2) optimization of integer use and new formula usage::         3) changhed name for "degree" input::         4) implemented "round" function for more precision, internal work on 3 digit:::: 0.1   4/9/2013   ::         First version that use 2 decimal for result e input in integer degree::         for angle from 0 to 90 degree.::::         From Francesco Poscetti aka Einstein1969::::         NOTE: This Function allow you to calculate almost all other common ::         trigonometric function. Uses the Taylor/Maclaurin function.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Setlocal   REM.--function body   set /a "d=%~1 %% 360"   if %d% lss 0   ( set /a d=-d, rr=-1 ) else ( set /a rr=1 )   if %d% geq 180 ( set /a d=d-180, rr=-rr )   if %d% gtr 90  ( set /a d=180-d)   if %d% leq 45 (      set /a "y=(((x=3141592*d/180/(o=1000))-x*x*x/6/(o*o))+5)/10*rr"   ) else (      set /a "y=(((o=1000)-(x=3141592*(90-d)/180/o)*x/2/o+x*x*x/100/2*x/12/(o*o)/10)+4)/10*rr"         )(Endlocal & REM -- Return Values    If "%~2" neq "" (Set %~2=%y%) Else Echo %y%)Goto:EOF::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::``

EDIT: There where !d! ... replaced with %d%

Einstein1969
Last edited by einstein1969 on 31 Mar 2014 14:01, edited 3 times in total.

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

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

Can I ask why there are all those endlocal?

The only way to pass arguments to the macro is the SET statement in the ELSE branch at the end of the macro. As you can see there is also a SETLOCAL EnableDelayedExpansion that you need to expand variables inside of the command line block in the associated IF branch.
Because of all the other IF statements you need an ENDLOCAL at each point where the macro execution could end up. Otherwise the delayed variable expansion is still valid for the rest of your code (with all its side effects for strings that include exclamation marks).

Regards
aGerman

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

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

Some time ago I used a method to perform operations with SIN(x) over degree values (0-360) using only integer operations, that is to say, I always used the result of SIN(x) to multiply it by an integer value and get an integer as result. I used the same method in a Batch program later that I posted in this post (this part appear after 6-CursorPos.exe.hex program):
Aacini wrote:We may even draw trigonometric functions if we define a table of SIN(x) values multiplied by a standard factor (ie: 0xFFFF or 65535):

This way, to get SIN(x) multiplied by a number, just multiply the SIN[%x%] table value by the number and shift the result 16 bits to the right. This method correctly works with signed values because SET /A right shift operation is an aritmethic one (SAR), although the documentation indicate that is "logical shift" (SHR).

For example:

Code: Select all

``@echo off setlocal EnableDelayedExpansioncall :DefineSinTableset st=For /L %%i in (1,1,52) do set st=#!st!For /L %%x in (0,4,90) do (   set /a "int_sinx_result=(SIN[%%x]*52)>>16"   call set st_=%%st:~0,-!int_sinx_result!%%   echo(!st_!)For /L %%x in (90,-4,0) do (    set /a "int_sinx_result=(SIN[%%x]*52)>>16"   call set st_=%%st:~0,-!int_sinx_result!%%   echo(!st_!)goto :EOF:DefineSinTablerem Definition of SIN table values (SIN(x)*65535) for 0-360 degreesrem Antonio Perez Ayalaset Quad1=0for %%a in ( 1144  2287  3430  4572  5712  6850  7987  9121 10252 11380 12505 13626 14742 15855 16962             18064 19161 20252 21336 22415 23486 24550 25607 26656 27697 28729 29753 30767 31772 32768             33754 34729 35693 36647 37590 38521 39441 40348 41243 42126 42995 43852 44695 45525 46341             47143 47930 48703 49461 50203 50931 51643 52339 53020 53684 54332 54963 55578 56175 56756             57319 57865 58393 58903 59396 59870 60326 60764 61183 61584 61966 62328 62672 62997 63303             63589 63856 64104 64332 64540 64729 64898 65048 65177 65287 65376 65446 65496 65526 65535           ) do (   set /A Quad1+=1, Quad2=180-Quad1, Quad3=180+Quad1, Quad4=360-Quad1   set SIN[!Quad1!]=%%a   set SIN[!Quad2!]=%%a   set SIN[!Quad3!]=-%%a   set SIN[!Quad4!]=-%%a)for %%a in (0 180 360) do set SIN[%%a]=0exit /B``

Result:

Code: Select all

``###############################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################``

Antonio

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

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

@aGerman

Thank you very much for the explanation aGerman. In the new version I have included the use of expanded variables directly,
then the approach should be different? The code of the new version will come soon.

@Aacini
Aacini I appreciate your intervention. I wanted to ask an explanation of the method used by you to maintain information of the decimal. The number of 16-bit has been chosen as a criterion?

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

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

einstein1969 wrote:@Aacini
Aacini I appreciate your intervention. I wanted to ask an explanation of the method used by you to maintain information of the decimal. The number of 16-bit has been chosen as a criterion?

The original method was used in an assembly language program that calculate a series of (x,y) points to draw circles and ellipses via drawpoly BGI function. The radius was a 16-bits number that was multiplied by the value of the Sin table giving the 32-bits result in two separated 16-bits registers, so I directly took the high-order register of the result with no additional operation. This method was at least as fast as the original circle BGI function!

The 16-bits Sin(x) table, (Sin(x)*65535 as unsigned 16-bits value, equivalent to a little less than 5 decimal digits, but more than 4) was enough to draw perfect circles in the screen no matter the radius. If you need more precision, you may use more bits for the Sin(x) table and less for the factor. For example, you may use 24 bits for the Sin(x) table (Sin(x)*16777215, equivalent to more than 7 decimal digits) and 7 bits for the factor (a maximum value of 127), and perform the operation this way: set /A result=(SIN[!x!]*factor)>>24.

Antonio