multiplication - Batch file multiply positive variables return a negative number -
i've been working on batch polygon area calculator , got problem. need multiply 2 variables, return negative number if 2 positive variables large.
here's example: 999999*999999
returns -729379967
.
code goes below:
rem calc square area :polysqu cls echo polygon area calculator /l %%p in (1,1,57) echo. set /p "inputpolygoncalsqu=enter 1 of line's length in cm :" set /a squarea=inputpolygoncalsqu * inputpolygoncalsqu cls echo polygon area calculator /l %%p in (1,1,57) echo. echo area of square %squarea% cm2. pause goto :polygoncal
it seemed command
set /a squarea="inputpolygoncalsqu * inputpolygoncalsqu
doesn't calculate properly.
as others pointed out, batch-file natively supports 32-bit signed integer arithmetics only.
the following code constitutes work-around multiplying non-negative numbers greater limit of 232 − 1 = 2147483647, using pure batch-file commands (let call multiply.bat
):
@echo off setlocal enableextensions disabledelayedexpansion rem // define arguments here: set "num1=%~1" set "num2=%~2" set "num3=%~3" set "num4=%~4" if defined num1 set "num1=%num1:"=""% if defined num2 set "num2=%num2:"=""% if defined num3 set "num3=%num3:"=% call :val_args num1 num2 num4 || exit /b 1 rem // define constants here: set /a "dig=4" & set "pad=" setlocal enabledelayedexpansion /l %%j in (1,1,%dig%) set "pad=!pad!0" endlocal & set "pad=%pad%" rem // determine string lengths: call :str_len len1 num1 call :str_len len2 num2 set /a "len1=(len1-1)/dig*dig" set /a "len2=(len2-1)/dig*dig" set /a "lim=len1+len2+dig" /l %%i in (0,%dig%,%lim%) set /a "res[%%i]=0" rem // perform block-wise multiplication: setlocal enabledelayedexpansion /l %%j in (0,%dig%,%len2%) ( /l %%i in (0,%dig%,%len1%) ( set /a "idx=%%i+%%j" if %%i equ 0 (set "aux1=-%dig%") else ( set /a "aux1=%dig%+%%i" & set "aux1=-!aux1!,-%%i" ) if %%j equ 0 (set "aux2=-%dig%") else ( set /a "aux2=%dig%+%%j" & set "aux2=-!aux2!,-%%j" ) /f "tokens=1,2" %%m in ("!aux1! !aux2!") ( set "aux1=!num1:~%%m!" & set "aux2=!num2:~%%n!" ) call :no_lead0 aux1 !aux1! call :no_lead0 aux2 !aux2! set /a "res[!idx!]+=aux1*aux2" set /a "nxt=idx+dig, dit=dig*2" /f "tokens=1,2,3" %%m in ("!idx! !nxt! !dit!") ( set "aux=!res[%%m]:~-%%o,-%dig%!" set /a "res[%%n]+=aux" set "res[%%m]=!res[%%m]:~-%dig%!" call :no_lead0 res[%%m] !res[%%m]! ) ) ) rem // build resulting product: set "res=" & set "aux=" /l %%i in (0,%dig%,%lim%) ( set /a "res[%%i]+=aux" set /a "nxt=%%i+dig" /l %%j in (!nxt!,%dig%,!nxt!) ( set "aux=!res[%%i]:~-%%j,-%dig%!" ) set "res[%%i]=%pad%!res[%%i]!" set "res=!res[%%i]:~-%dig%!!res!" ) endlocal & set "res=%res%" call :no_lead0 res %res% rem // return resulting product: echo(%res% if defined num3 ( endlocal set "%num3%=%res%" ) else ( endlocal ) exit /b :no_lead0 rtn_var val_num rem // remove leading zeros number: /f "tokens=* delims=0" %%z in ("%~2") ( set "%~1=%%z" & if not defined %~1 set "%~1=0" ) exit /b 0 :str_len rtn_length ref_string rem // retrieve length of string: setlocal enabledelayedexpansion set "str=!%~2!" if not defined str (set /a len=0) else (set /a len=1) %%l in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) ( if defined str ( set "int=!str:~%%l!" if not "!int!"=="" set /a len+=%%l & set "str=!int!" ) ) endlocal & set "%~1=%len%" exit /b 0 :val_args ref_arg1 ref_arg2 ref_arg3 rem // check arguments validity: if not defined %~1 >&2 echo error: few arguments given! & exit /b 1 if not defined %~2 >&2 echo error: few arguments given! & exit /b 1 if defined %~3 >&2 echo error: many arguments given! & exit /b 1 (call echo "%%%~1%%" | > nul findstr /r /c:"^\"[0-9][0-9]*\" $") || ( >&2 echo error: argument 1 not purely numeric! & exit /b 1 ) (call echo "%%%~2%%" | > nul findstr /r /c:"^\"[0-9][0-9]*\" $") || ( >&2 echo error: argument 2 not purely numeric! & exit /b 1 ) exit /b 0
to use provide 2 numbers multiply command line arguments; instance:
multiply.bat 999999 999999
the resulting product returned on console:
999998000001
if provide third argument, product assigned variable name; example:
multiply.bat 999999 999999 squarea
this sets variable squarea
resulting value. latter still returned on console.
silently assign variable without additional console output, redirect nul
device:
multiply.bat 999999 999999 squarea > nul
Comments
Post a Comment