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, 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 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

Popular posts from this blog

jOOQ update returning clause with Oracle -

java - Warning equals/hashCode on @Data annotation lombok with inheritance -

java - BasicPathUsageException: Cannot join to attribute of basic type -