べき乗は、ふつうはバイナリ法を使うと速くなるのですが、バッチファイルの場合は事情が変わってきます。バッチファイルではforループが相対的に速いため単純に一つずつ掛けていくのが速くなりやすいのです。
@echo off set /a N = 100 set /a e = 128 call :start_time for /L %%i in (1, 1, %N%) do call :pow1 2 %e% 3 echo %ERRORLEVEL% call :check_time call :start_time for /L %%i in (1, 1, %N%) do call :pow2 2 %e% 3 echo %ERRORLEVEL% call :check_time rem // 単純法 :pow1 setlocal set /a m = 1 for /L %%i in (1, 1, %2) do ( set /a m *= %1 set /a m %%= %3 ) exit /b %m% rem // バイナリ法 :pow2 setlocal if %2 == 0 exit /b 1 set /a half_e = %2 / 2 call :pow2 %1 %half_e% %3 set /a m = %ERRORLEVEL% set /a is_odd = %2 %% 2 if %is_odd% == 1 ( set /a s = %m% * %m% * %1 %% %3 ) else ( set /a s = %m% * %m% %% %3 ) exit /b %s% rem // 以下略
指数 | 単純法 | バイナリ法 |
---|---|---|
4 | 0.25s | 1.32s |
8 | 0.28s | 1.71s |
16 | 0.42s | 2.08s |
32 | 0.55s | 2.47s |
64 | 0.81s | 2.88s |
128 | 1.36s | 3.22s |
256 | 2.33s | 3.64s |
512 | 4.49s | 4.14s |
1024 | 8.81s | 4.56s |
ここでは500くらいに分岐点があるようです。
大きい指数の場合は途中までバイナリ法を使い、指数が小さくなったら単純法を使えばよいでしょう。64を分岐点にすると倍くらい速くなるようです。しかし、あまり速くはならないですね。
@echo off set /a N = 100 set /a e = 1024 call :start_time for /L %%i in (1, 1, %N%) do call :pow 2 %e% 3 echo %ERRORLEVEL% call :check_time exit /b 0 :pow setlocal if %2 == 0 exit /b 1 set /a half_e = %2 / 2 if %half_e% GTR 64 ( call :pow %1 %half_e% %3 ) else ( call :pow_simple %1 %half_e% %3 ) set /a m = %ERRORLEVEL% set /a is_odd = %2 %% 2 if %is_odd% == 1 ( set /a s = %m% * %m% * %1 %% %3 ) else ( set /a s = %m% * %m% %% %3 ) exit /b %s% :pow_simple setlocal set /a m = 1 for /L %%i in (1, 1, %2) do ( set /a m *= %1 set /a m %%= %3 ) exit /b %m% :start_time call :get_time set /a __t0 = %ERRORLEVEL% exit /b 0 :check_time setlocal call :get_time set /a t = %ERRORLEVEL% - %__t0% if %t% LSS 10 ( echo 0.0%t%s ) else ( if %t% LSS 100 ( echo 0.%t%s ) else ( echo %t:~0,-2%.%t:~-2%s ) ) 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%