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

Problem 14


コラッツに戻りましょう。この問題も1に辿りつくまでに何回同じ操作を繰り返せばよいかわかりません。以下では、70回繰り返して、その間に1に辿りつかなかったらまた70回繰り返す、というフローにしています。
また、6の倍数で場合わけをしています。例えば、5余る場合、6n+5 ← 12n+10 ← 4n+3となるので、これより小さくて2つ長い数があります。つまり5余る場合は考えなくてよいことになります。それから長さを求めるときに4で割ったときの余りを考えると速くなります。例えば、余りが3のとき4n+3 → 12n+10 → 6n+5 → 18n+16 → 9n+8と4つ進めることができます。
これでも1時間半かかってしまいました。もう少しくらいは速くなりそうですが、1時間は切れそうにないです。

@echo off

setlocal enabledelayedexpansion
call :start_time
set /a N = 1000000
set /a half = %N% / 2
set /a delta = 70
set /a s = 0
for /L %%i in (%half%, 1, %N%) do (
    call :Collatz %%i
    if !ERRORLEVEL! GTR !s! (
        set /a s = !ERRORLEVEL!
        set /a max_n = %%i
    )
)
echo %max_n%
call :check_time
exit /b 0

:Collatz
    setlocal
    set /a r = %1 %% 6
    if %r% GEQ 4 exit /b 0
    if %r% == 2 exit /b 0
    
    set /a m = %1
    set /a begin = 1
    set /a end = %delta%
    set /a k = 0
    :loop_Collatz
        for /L %%k in (%begin%, 1, %end%) do (
            if !m! LEQ 2 (
                set /a k += !m!
                exit /b !k!
            )
            set /a r = !m! %% 4
            if !r! == 0 (
                set /a m /= 4
                set /a k += 2
            ) else (
                if !r! == 3 (
                    set /a m = !m! / 4 * 9 + 8
                    set /a k += 4
                ) else (
                    set /a m = !m! / 4 * 3 + !r!
                    set /a k += 3
                )
            )
        )
        set /a begin += %delta%
        set /a end += %delta%
        goto :loop_Collatz

: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%