バッチファイルでProject Euler(17)

時間計測できるようになったので、ベンチマークしてみましょう。1〜1000の和を4つの方法で求めます。それぞれ、for、goto、for+callで回したもの、そして再帰を使ったものです。

500500
for : .07s
500500
goto : 1.57s
500500
for+call : 1.38s
500500
recursion : 3.30s

forで回すのが圧倒的に速く、gotoやcallで飛ぶと遅くなるようです。あまり素直に使える場面は少ないのですが、使えるところはforを使ったほうがよいようです。再帰はさすがに遅いですね。

@echo off

setlocal
set /a N = 1000
call :get_time
set /a t = %ERRORLEVEL%
call :sum1 %N%
echo %ERRORLEVEL%
call :get_time
set /a t = %ERRORLEVEL% - %t%
echo for : %t:~0,-2%.%t:~-2%s

call :get_time
set /a t = %ERRORLEVEL%
call :sum2 %N%
echo %ERRORLEVEL%
call :get_time
set /a t = %ERRORLEVEL% - %t%
echo goto : %t:~0,-2%.%t:~-2%s

call :get_time
set /a t = %ERRORLEVEL%
call :sum3 %N%
echo %ERRORLEVEL%
call :get_time
set /a t = %ERRORLEVEL% - %t%
echo for+call : %t:~0,-2%.%t:~-2%s

call :get_time
set /a t = %ERRORLEVEL%
call :sum4 1 %N% 0
echo %ERRORLEVEL%
call :get_time
set /a t = %ERRORLEVEL% - %t%
echo recursion : %t:~0,-2%.%t:~-2%s
exit /b 0

:sum1
    setlocal
    set /a s = 0
    for /L %%i in (1, 1, %1) do set /a s += %%i
    exit /b %s%

:sum2
    setlocal
    set /a s = 0
    set /a k = 1
    :loop_sum
        set /a s += %k%
        set /a k += 1
        if %k% LEQ %1 goto :loop_sum
    exit /b %s%

:sum3
    setlocal
    set /a s = 0
    for /L %%i in (1, 1, %1) do call :add %%i
    exit /b %s%

:sum4
    setlocal
    if %1 GTR %2 exit /b 0
    set /a first = %1 + 1
    call :sum4 %first% %2
    set /a s = %1 + %ERRORLEVEL%
    exit /b %s%

:add
    set /a s += %1
    exit /b 0

:get_time
    setlocal
    set t=%TIME%
    set /a h = %t:~0,2%
    set /a m = 1%t:~3,2% %% 100
    set /a s = 1%t:~6,2% %% 100
    set /a ss = 1%t:~-2% %% 100
    set /a ret = ((%h% * 60 + %m%) * 60 + %s%) * 100 + %ss%
    exit /b %ret%