バッチファイルで浮動小数点数演算(3)

乗算

仮数部を12ビットずつにわけて掛け算すれば簡単です。その上24ビットを取ります。四捨五入はしていません。指数部は単純に足し算です。最後に符号をつけます。

@echo off

setlocal enabledelayedexpansion
call :int2float -3
set /a a = %ERRORLEVEL%
call :int2float -130
set /a b = %ERRORLEVEL%
call :multiply_float %a% %b%
call :float2int %ERRORLEVEL%
echo %ERRORLEVEL%
exit /b 0

:int2float
    setlocal
    call :encode_float %1 24
    exit /b %ERRORLEVEL%

:float2int
    setlocal
    call :decode_float %1
    if %exp% LSS 24 (
        set /a n = "sig >> (24 - exp)"
    ) else (
        set /a n = "sig << (exp - 24)"
    )
    exit /b %n%

:multiply_float
    setlocal
    call :decode_float %1 1
    call :decode_float %2 2
    
    set /a sign1 = 0
    if %sig1% LSS 0 (
        set /a sign1 = 1
        set /a sig1 = -%sig1%
    )
    set /a sign2 = 0
    if %sig2% LSS 0 (
        set /a sign2 = 1
        set /a sig2 = -%sig2%
    )
    
    set /a a1 = "sig1 >> 12"
    set /a b1 = "sig1 & 0xFFF"
    set /a a2 = "sig2 >> 12"
    set /a b2 = "sig2 & 0xFFF"
    
    set /a m3 = %b1% * %b2%
    set /a m2 = %a1% * %b2% + %a2% * %b1% + "(m3 >> 12)"
    set /a m1 = %a1% * %a2% + "(m2 >> 12)"
    
    set /a sign = "sign1 ^ sign2"
    if %sign% == 1 set /a m1 = -%m1%
    set /a exp = %exp1% + %exp2%
    call :encode_float %m1% %exp%
    exit /b %ERRORLEVEL%

:encode_float
    setlocal
    if %1 == 0 exit /b 0
    if %1 GTR 0 (
        set /a sig = %1
    ) else (
        set /a sig = -%1
    )
    set /a sign = "%1 & 0x80000000"
    set /a e = %2
    :loop_encode_float
        if %sig% GEQ 0x1000000 (
            set /a "sig >>= 1"
            set /a e += 1
            goto :loop_encode_float
        )
        if %sig% LSS 0x800000 (
            set /a "sig <<= 1"
            set /a e -= 1
            goto :loop_encode_float
        )
    
    set /a sig -= 0x800000
    set /a code = "sig | ((e + 127) << 23) | sign"
    exit /b %code%

:decode_float
    set /a sig%2 = "(%1 & 0x7FFFFF) + 0x800000"
    set /a exp%2 = "((%1 >> 23) & 0xFF) - 127"
    set /a sign = "%1 >> 31"
    if %sign% == -1 set /a sig%2 = "-sig%2"
    exit /b 0