example of implementation of
sqrt(x):
input
32 bit integer output
32bit integer
by Antonio Acini:
Code: Select all
@echo off
setlocal EnableDelayedExpansion
set /A number=%1
set /A iter1=number/2+1
rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
)
echo Sqrt(%number%) = %sqrt%
modified the first set to set /A (sugg. by dbenham)
modified the first iter1 adding + 1
backup of Judago STR_MATH.BAT v2.0:
Code: Select all
@ECHO Off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
if "%~3"=="" (
echo.
echo. STR_MATH.BAT v2.0
echo.
echo. Large number and floating point work around script for Addition,
echo. Subtraction, Division, Multiplaction, Modulus and exponents.
echo. Floating point and negative numbers supported.
echo.
echo. Usage:
echo. STR_MATH.BAT {Number} {+-XM} {Number}
echo. STR_MATH.BAT {Number} {/Y} {Number} [n max decimal places]
echo.
echo. Division and certain negative exponents default to a maximum
echo. of ten decimal places of output. An optional user defined max
echo. can be input as the fourth number when applicable.
echo.
echo. No rounding is performed on output of division, the number
echo. is only truncated. For example a result of 0.1257 with three
echo. places will return 0.125 NOT 0.126.
echo.
echo. Square brackets can be used on negative base exponents instead
echo. of parentheses if needed:
echo. STR_MATH [-5] Y 10
echo. STR_MATH -5 Y 10
echo.
echo. Fractional exponents are not supported.
echo.
echo. Results are not garanteed. Provided AS-IS.
echo.
echo. Output Will be echo'd, a "for /f" loop can be used to
echo. capture the output. An example is as follows, be sure
echo. NOT to use the /A switch to SET if using a variable.
echo.
echo. FOR /F %%A IN ^(' STR_MATH.BAT 50.265 X 1.36 '^) DO SET RESULT=%%A
echo.
echo. Variables must be expanded when passed to the script, like so:
echo.
echo. FOR /F %%A IN ^(' STR_MATH.BAT %%number1%% / %%number2%% '^) DO SET RESULT=%%A
echo.
echo. Judago 2011, 2015 ^& 2016.
goto :eof
)
set _INP_NUM1=
set _INP_NUM2=
set _INP_NEG1=
set _INP_NEG2=
set _INP_OP=
set _RET_NUM=
set _OUT_DP=
set _OUT_NEG=
set _INP_EXP_PAR=0
set _INP_EXP_DIV=0
set "_INP_NUM1=%~1"
set "_INP_NUM2=%~3"
set "_INP_OP=%~2"
if /i "%~2"=="*" (
set _INP_OP=x
)
if /i "%~2"=="%%" (
set _INP_OP=m
)
rem Default number of digits for division
set _DIV_DP=10
rem ***** Start Input validation *****
for %%z in ("/" "y") do (
if /i "%~2"=="%%~z" if not "%~4"=="" (
for /f "delims=0123456789 tokens=1*" %%a in ("A0%~4") do (
if "%%b"=="" (
for /f "tokens=1* delims=0" %%c in ("A0%~4") do (
if "%%d"=="" (
set _DIV_DP=0
) else set _DIV_DP=%%d
)
) else (
1>&2 Echo ERROR: "%~4" not detected as a valid number of decimal places
goto :eof
)
)
shift /4
)
)
if not "%~4"=="" (
1>&2 echo ERROR: Too many arguments: "%~4"
goto :eof
)
if not defined _INP_NUM1 (
1>&2 echo ERROR: Invalid Input: "!_INP_NUM1!"
goto :eof
)
if not defined _INP_NUM2 (
1>&2 echo ERROR: Invalid Input: "!_INP_NUM2!"
goto :eof
)
if not defined _INP_OP (
1>&2 echo ERROR: Invalid Operator: "!_INP_OP!"
goto :eof
)
if not "!_INP_OP:~1!"=="" (
1>&2 echo ERROR: Invalid Operator: "!_INP_OP!"
goto :eof
)
rem **** check for brackets on base exponent ****
if /i "!_INP_OP!"=="Y" (
for /f "tokens=1,2* delims=[]" %%a in ("A!_INP_NUM1!A]") do (
if "%%a%%c"=="AA]" (
set _INP_EXP_PAR=1
set _INP_NUM1=!_INP_NUM1:[=!
set _INP_NUM1=!_INP_NUM1:]=!
)
)
)
rem ***** / ***** Start Negitive input ***** \ *****
for %%a in (1 2) do (
if "!_INP_NUM%%a:~0,1!"=="-" if not "!_INP_NUM%%a:~1!"=="" (
set _INP_NUM%%a=!_INP_NUM%%a:~1!
set _INP_NEG%%a=-
) else (
1>&2 echo ERROR: Invalid input: "!_INP_NUM%%a!"
goto :eof
)
)
if not defined _INPUT_NEG1 set _INP_EXP_PAR=0
rem ***** \ ***** End Negitive input ***** / *****
rem ****** Bad characters ******
for /f "tokens=1* delims=0123456789." %%a in ("A0!_INP_NUM1!!_INP_NUM2!") do (
if not "%%b"=="" (
1>&2 echo ERROR: Invalid input: "!_INP_NUM1!" **OR** "!_INP_NUM2!"
goto :eof
)
)
rem ***** Fractional exponenets aren't supported ******
for /f "tokens=1,2* delims=." %%a in ("0.!_INP_NUM1!!_INP_NUM2!") do (
if not "%%c"=="" (
1>&2 echo ERROR: Fractional exponents are not supported
goto :eof
)
)
for %%a in (1 2) do (
for /f "tokens=1-3 delims=." %%b in ("0!_INP_NUM%%a!0") do (
if not "%%d"=="" (
1>&2 echo ERROR: Invalid input: "!_INP_NUM%%a!"
goto :eof
)
)
)
for /f "tokens=1* delims=/Xx+-mMYy" %%a in ("A+!_INP_OP!") do (
if not "%%b"=="" (
1>&2 echo ERROR: Invalid operator: "!_INP_OP!"
goto :eof
)
)
rem ***** End input validation *****
rem ***** Start Remove leading zero's / Return for zero sums *****
for %%a in (1 2) do (
for /f "tokens=1* delims=0" %%b in ("A0!_INP_NUM%%a!") do (
if "%%c"=="" (
if /i "!_INP_OP!"=="x" echo 0
if "!_INP_OP!"=="/" (
if %%a==2 (
1>&2 Echo ERROR: Divide by zero
goto :eof
) else echo 0
) else if /i "!_INP_OP!"=="m" (
if %%a==2 (
1>&2 Echo ERROR: Divide by zero
goto :eof
) else echo 0
) else if "!_INP_OP!"=="-" (
if %%a==1 (
if defined _INP_NEG2 (
echo !_INP_NUM2!
) else echo -!_INP_NUM2!
) else (
echo !_INP_NEG1!!_INP_NUM1!
)
) else if "!_INP_OP!"=="+" (
if %%a==1 (
echo !_INP_NEG2!!_INP_NUM2!
) else echo !_INP_NEG1!!_INP_NUM1!
) else if /i "!_INP_OP!"=="y" (
if "%%a"=="1" (
if "!_INP_NEG2!"=="-" (
1>&2 echo ERROR: Negative exponents of zero are undefined.
) else (
echo 0
)
) else (
if "!_INP_EXP_PAR!"=="1" (
echo 1
) else (
echo !_INP_NEG1!1
)
)
)
goto :eof
) else set _INP_NUM%%a=%%c
)
)
rem ***** End Remove leading zero's / Return for zero sums *****
rem ***** Start Floating point normalisation *****
for %%a in (1 2) do (
if "!_INP_NUM%%a:~0,1!"=="." set _INP_NUM%%a=0!_INP_NUM%%a!
if "!_INP_NUM%%a:~-1!"=="." set _INP_NUM%%a=!_INP_NUM%%a!0
for /l %%b in (0 1 9) do set _INP_NUM%%a=!_INP_NUM%%a:%%b=%%b !
for %%c in (!_INP_NUM%%a!) do set /a _INP_LEN%%a+=1
set _INP_NUM%%a=!_INP_NUM%%a: =!
if "!_INP_NUM%%a!"=="!_INP_NUM%%a:.=!" (
set _INP_DP%%a=0
) else (
for /l %%d in (!_INP_LEN%%a! -1 1) do (
if not defined _INP_DP%%a if "!_INP_NUM%%a:~%%d,1!"=="." (
set /a _INP_DP%%a=!_INP_LEN%%a! - %%d
)
)
)
set _INP_NUM%%a=!_INP_NUM%%a:.=!
)
if !_INP_DP1! gtr !_INP_DP2! (
set /a _OUT_DP=_INP_DP1 - 1
) else set /a _OUT_DP=_INP_DP2 - 1
for /l %%a in (!_INP_DP1! 1 !_OUT_DP!) do set _INP_NUM1=!_INP_NUM1!0
for /l %%a in (!_INP_DP2! 1 !_OUT_DP!) do set _INP_NUM2=!_INP_NUM2!0
rem ***** End Floating point normalisation *****
rem ***** Start Negitive output checking *****
if /i "!_INP_OP!"=="x" (
if "!_INP_NEG1!!_INP_NEG2!"=="-" set _OUT_NEG=-
) else if "!_INP_OP!"=="+" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" set _OUT_NEG=-
if defined _INP_NEG2 if not defined _INP_NEG1 (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
set _OUT_NEG=-
)
set _INP_OP=-
)
if defined _INP_NEG1 if not defined _INP_NEG2 (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
) else if "!_GTR_RES!"=="1" set _OUT_NEG=-
set _INP_OP=-
)
) else if "!_INP_OP!"=="-" (
if "!_INP_NEG1!!_INP_NEG2!"=="" (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
set _OUT_NEG=-
)
)
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
) else if "!_GTR_RES!"=="1" set _OUT_NEG=-
)
if defined _INP_NEG2 if not defined _INP_NEG1 set _INP_OP=+
if defined _INP_NEG1 if not defined _INP_NEG2 (
set _OUT_NEG=-
set _INP_OP=+
)
) else if "!_INP_OP!"=="/" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" set _OUT_NEG=
if "!_INP_NEG1!!_INP_NEG2!"=="-" set _OUT_NEG=-
) else if /i "!_INP_OP!"=="M" (
if defined _INP_NEG1 set _OUT_NEG=-
) else if /i "!_INP_OP!"=="Y" (
if "!_INP_EXP_PAR!"=="0" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
set _OUT_NEG=-
set _INP_EXP_DIV=1
) else if "!_INP_NEG2!"=="-" (
set _INP_EXP_DIV=1
) else if "!_INP_NEG1!"=="-" (
set _OUT_NEG=-
)
) else (
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
for %%z in (1 3 5 7 9) do (
if "!_INP_NUM2:~-1!"=="%%z" set _OUT_NEG=-
)
set _INP_EXP_DIV=1
) else if "!_INP_NEG2!"=="-" (
set _OUT_NEG=-
set _INP_EXP_DIV=1
) else if "!_INP_NEG1!"=="-" (
for %%z in (1 3 5 7 9) do (
if "!_INP_NUM2:~-1!"=="%%z" set _OUT_NEG=-
)
)
)
)
rem ***** End Negitive output checking *****
Rem Main calling routines
if "!_INP_OP!"=="-" (
call :subtract %_INP_NUM1% %_INP_NUM2%
) else if "!_INP_OP!"=="+" (
call :add %_INP_NUM1% %_INP_NUM2%
) else if /i "!_INP_OP!"=="X" (
set /a _OUT_DP=^(_OUT_DP * 2^) + 1
call :multiply %_INP_NUM1% %_INP_NUM2%
) else if /i "!_INP_OP!"=="m" (
call :divide %_INP_NUM1% %_INP_NUM2% 0 m
) else if "!_INP_OP!"=="/" (
call :divide %_INP_NUM1% %_INP_NUM2% %_DIV_DP%
set /a _OUT_DP=_DIV_DP - 1
) else if /i "!_INP_OP!"=="Y" (
call :EXPONENT !_INP_NUM1! !_INP_NUM2!
if "!_INP_EXP_DIV!"=="1" (
call :DIVIDE 1 !_RET_NUM! !_DIV_DP!
set /a _OUT_DP=_DIV_DP - 1
)
) else (
1>&2 echo ERROR: Unknown operator.
goto :eof
)
rem finishing up.....
set _FIN_FLAG=
if not defined _OUT_DP (
set _OUT_DP=0
) else set /a _OUT_DP+=1
if not "!_OUT_DP!"=="0" (
for /l %%a in (1 1 !_OUT_DP!) do if "!_RET_NUM:~%_OUT_DP%!"=="" set _RET_NUM=0!_RET_NUM!
set _RET_NUM=!_RET_NUM:~0^,-%_OUT_DP%!.!_RET_NUM:~-%_OUT_DP%!
for /l %%a in (!_OUT_DP! -1 1) do (
if "!_RET_NUM:~-1!"=="0" set _RET_NUM=!_RET_NUM:~0^,-1!
if "!_RET_NUM:~-1!"=="." set _RET_NUM=!_RET_NUM:~0^,-1!
)
)
for /f "tokens=1* delims=0" %%a in ("A0!_RET_NUM!") do (
if "%%b"=="" (
set _RET_NUM=0
) else set _RET_NUM=%%b
)
if "!_RET_NUM:~0,1!"=="." set _RET_NUM=0!_RET_NUM!
IF NOT DEFINED _RET_NUM SET _RET_NUM=0
echo %_OUT_NEG%%_RET_NUM%
goto :eof
rem ***********************************************************************
rem ****************************** Subroutines ****************************
rem ***********************************************************************
:SUBTRACT
set _SUB_NUM1=%~1
set _SUB_NUM2=%~2
for %%a in (CHA RES LEN1 LEN2 CAR TOT) do set _SUB_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _SUB_NUM%%a=!_SUB_NUM%%a:%%b=%%b !
for %%c in (!_SUB_NUM%%a!) do set /a _SUB_LEN%%a+=1
set _SUB_NUM%%a=!_SUB_NUM%%a: =!
)
if !_SUB_LEN1! gtr !_SUB_LEN2! (
set /a _SUB_LEN=_SUB_LEN1 - 1
) else set /a _SUB_LEN=_SUB_LEN2 - 1
for /l %%b in (!_SUB_LEN1! 1 !_SUB_LEN!) do set _SUB_NUM1=0!_SUB_NUM1!
for /l %%b in (!_SUB_LEN2! 1 !_SUB_LEN!) do set _SUB_NUM2=0!_SUB_NUM2!
for /l %%a in (!_SUB_LEN! -1 0) do (
set /a _SUB_RES=!_SUB_NUM1:~%%a,1! - !_SUB_NUM2:~%%a,1!
if !_SUB_RES! lss 0 (
set _SUB_TAKE=
for /l %%b in (%%a -1 0) do if not defined _SUB_TAKE (
if not "%%b"=="%%a" (
if not "!_SUB_NUM1:~%%b,1!"=="0" (
set /a _SUB_CHA=!_SUB_NUM1:~%%b,1! - 1
set /a _SUB_TAKE=%%b + 1
for %%c in (!_SUB_TAKE!) do set _SUB_NUM1=!_SUB_NUM1:~0,%%b!!_SUB_CHA!!_SUB_NUM1:~%%c!
set /a _SUB_RES=1!_SUB_NUM1:~%%a,1! - !_SUB_NUM2:~%%a,1!
) else (
set /a _SUB_CHA=%%b + 1
for %%c in (!_SUB_CHA!) do set _SUB_NUM1=!_SUB_NUM1:~0,%%b!9!_SUB_NUM1:~%%c!
)
)
)
)
set _SUB_TOT=!_SUB_RES!!_SUB_TOT!
)
for /f "tokens=1* delims=0" %%a in ("A0!_SUB_TOT!") do set _SUB_TOT=%%b
if not defined _SUB_TOT set _SUB_TOT=0
set _RET_NUM=%_SUB_TOT%
goto :eof
:ADD
set _ADD_NUM1=%~1
set _ADD_NUM2=%~2
for %%a in (LEN1 LEN2 CAR TOT) do set _ADD_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _ADD_NUM%%a=!_ADD_NUM%%a:%%b=%%b !
for %%c in (!_ADD_NUM%%a!) do set /a _ADD_LEN%%a+=1
set _ADD_NUM%%a=!_ADD_NUM%%a: =!
)
if !_ADD_LEN1! gtr !_ADD_LEN2! (
set /a _ADD_LEN=_ADD_LEN1 - 1
) else set /a _ADD_LEN=_ADD_LEN2 - 1
for /l %%b in (!_ADD_LEN1! 1 !_ADD_LEN!) do set _ADD_NUM1=0!_ADD_NUM1!
for /l %%b in (!_ADD_LEN2! 1 !_ADD_LEN!) do set _ADD_NUM2=0!_ADD_NUM2!
for /l %%a in (!_ADD_LEN! -1 0) do (
set /a _ADD_CAR=_ADD_CAR + !_ADD_NUM1:~%%a,1! + !_ADD_NUM2:~%%a,1!
set _ADD_TOT=!_ADD_CAR:~-1!!_ADD_TOT!
set _ADD_CAR=!_ADD_CAR:~0,-1!
if not defined _ADD_CAR set _ADD_CAR=0
)
if !_ADD_CAR! gtr 0 set _ADD_TOT=!_ADD_CAR!!_ADD_TOT!
set _RET_NUM=%_ADD_TOT%
goto :eof
:MULTIPLY
set _MUL_NUM1=%1
set _MUL_NUM2=%2
for %%a in (CAR TOT) do set _MUL_%%a=0
for %%a in (X10 REV1 REV2) do set _MUL_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _MUL_NUM%%a=!_MUL_NUM%%a:%%b=%%b !
for %%c in (!_MUL_NUM%%a!) do set _MUL_REV%%a=%%c !_MUL_REV%%a!
)
for %%a in (!_MUL_REV1!) do (
set _MUL_ROW=!_MUL_X10!
for %%b in (!_MUL_REV2!) do (
set /a _MUL_CAR=^(%%a * %%b^) + _MUL_CAR
set _MUL_ROW=!_MUL_CAR:~-1!!_MUL_ROW!
set _MUL_CAR=!_MUL_CAR:~0,-1!
if not defined _MUL_CAR set _MUL_CAR=0
)
for /f "tokens=1* delims=0" %%c in ("A0!_MUL_CAR!!_MUL_ROW!") do (
if not "%%d"=="" (
call :ADD %%d !_MUL_TOT!
set _MUL_TOT=!_RET_NUM!
)
)
set _MUL_CAR=
set _MUL_X10=!_MUL_X10!0
)
set _RET_NUM=%_MUL_TOT%
goto :eof
:DIVIDE
for %%a in (LEN1 LEN2 X10 PAD) do set _DIV_%%a=
if /i not "%4"=="m" (
for /l %%a in (1 1 %3) do set _DIV_PAD=0!_DIV_PAD!
)
set _DIV_NUM1=%1!_DIV_PAD!
set _DIV_NUM2=%2
set _DIV_TOT=0
set _DIV_PRC=1
for %%a in (1 2) do (
for /f "tokens=1* delims=0" %%d in ("A0!_DIV_NUM%%a!") do set _DIV_NUM%%a=%%e
for /l %%b in (0 1 9) do set _DIV_NUM%%a=!_DIV_NUM%%a:%%b=%%b !
for %%c in (!_DIV_NUM%%a!) do set /a _DIV_LEN%%a+=1
set _DIV_NUM%%a=!_DIV_NUM%%a: =!
)
set /a _DIV_LEN1-=1
for /l %%a in (!_DIV_LEN2! 1 !_DIV_LEN1!) do set _DIV_X10=0!_DIV_X10!
:__DIVINL
call :ISGREATER %_DIV_NUM1% %_DIV_NUM2%%_DIV_X10%
if %_GTR_RES% leq 2 (
call :SUBTRACT %_DIV_NUM1% %_DIV_NUM2%%_DIV_X10%
set _DIV_NUM1=!_RET_NUM!
call :ADD %_DIV_TOT% 1%_DIV_X10%
set _DIV_TOT=!_RET_NUM!
) else if defined _DIV_X10 (
set _DIV_X10=!_DIV_X10:~1!
) else set _DIV_PRC=0
if "!_DIV_PRC!"=="1" goto :__DIVINL
if /i "%4"=="m" set _DIV_TOT=!_DIV_NUM1!
set _RET_NUM=%_DIV_TOT%
Goto :eof
:EXPONENT
set _EXP_SRL=
set _EXP_SQU=%2
set _EXP_TOT=%1
set _EXP_PRC=1
:__EXINL
call :DIVIDE !_EXP_SQU!0 2 0
set _EXP_SQU=%_RET_NUM%
if "%_EXP_SQU:~-1%"=="5" (
set _EXP_SRL=%_EXP_SRL% %_EXP_TOT%
)
set _EXP_SQU=%_EXP_SQU:~0,-1%
if "%_EXP_SQU%"=="" (
set _EXP_PRC=0
) else (
call :MULTIPLY %_EXP_TOT% %_EXP_TOT%
set _EXP_TOT=!_RET_NUM!
if "%_EXP_SQU%"=="3" (
set _EXP_SRL=!_EXP_SRL! !_EXP_TOT!
set _EXP_SQU=2
)
if "!_EXP_SQU!"=="2" (
call :MULTIPLY !_EXP_TOT! !_EXP_TOT!
set _EXP_TOT=!_RET_NUM!
for %%z in (!_EXP_SRL!) do (
call :MULTIPLY !_EXP_TOT! %%z
set _EXP_TOT=!_RET_NUM!
)
set _EXP_PRC=0
)
if "!_EXP_SQU!"=="1" (
set _EXP_PRC=0
)
)
if "!_EXP_PRC!"=="1" goto __EXINL
set _RET_NUM=!_EXP_TOT!
goto :eof
:ISGREATER
set _GTR_RES=
for /f "tokens=1* delims=0" %%a in ("A0%~1") do (
if "%%b"=="" (
set _GTR_NUM1=0
) else set _GTR_NUM1=%%b
)
for /f "tokens=1* delims=0" %%a in ("A0%~2") do (
if "%%b"=="" (
set _GTR_NUM2=0
) else set _GTR_NUM2=%%b
)
for %%a in (lEN1 lEN2) do set _GTR_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _GTR_NUM%%a=!_GTR_NUM%%a:%%b=%%b !
for %%c in (!_GTR_NUM%%a!) do set /a _GTR_lEN%%a+=1
set _GTR_NUM%%a=!_GTR_NUM%%a: =!
)
if !_GTR_lEN1! gtr !_GTR_lEN2! (
set _GTR_RES=1
) else if !_GTR_lEN2! gtr !_GTR_lEN1! (
set _GTR_RES=3
) else (
set /a _GTR_lEN1-=1
for /l %%a in (0 1 !_GTR_lEN1!) do (
if not defined _GTR_RES (
if !_GTR_NUM1:~%%a^,1! gtr !_GTR_NUM2:~%%a^,1! set _GTR_RES=1
if !_GTR_NUM2:~%%a^,1! gtr !_GTR_NUM1:~%%a^,1! set _GTR_RES=3
)
)
)
if not defined _GTR_RES set _GTR_RES=2
goto :eof
judago 2.1:
Code: Select all
@ECHO Off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
if "%~3"=="" (
echo.
echo. STR_MATH.BAT v2.1
echo.
echo. Large number and floating point work around script for Addition,
echo. Subtraction, Division, Multiplaction, Modulus and exponents.
echo. Floating point and negative numbers supported.
echo.
echo. Usage:
echo. STR_MATH.BAT {Number} {+-XM} {Number}
echo. STR_MATH.BAT {Number} {/Y} {Number} [n max decimal places]
echo.
echo. Division and certain negative exponents default to a maximum
echo. of ten decimal places of output. An optional user defined max
echo. can be input as the fourth number when applicable.
echo.
echo. No rounding is performed on output of division, the number
echo. is only truncated. For example a result of 0.1257 with three
echo. places will return 0.125 NOT 0.126.
echo.
echo. Square brackets can be used on negative base exponents instead
echo. of parentheses if needed:
echo. STR_MATH [-5] Y 10
echo. STR_MATH -5 Y 10
echo.
echo. Fractional exponents are not supported.
echo.
echo. Results are not garanteed. Provided AS-IS.
echo.
echo. Output Will be echo'd, a "for /f" loop can be used to
echo. capture the output. An example is as follows, be sure
echo. NOT to use the /A switch to SET if using a variable.
echo.
echo. FOR /F %%A IN ^(' STR_MATH.BAT 50.265 X 1.36 '^) DO SET RESULT=%%A
echo.
echo. Variables must be expanded when passed to the script, like so:
echo.
echo. FOR /F %%A IN ^(' STR_MATH.BAT %%number1%% / %%number2%% '^) DO SET RESULT=%%A
echo.
echo. Judago 2011, 2015 ^& 2016.
goto :eof
)
set _INP_NUM1=
set _INP_NUM2=
set _INP_NEG1=
set _INP_NEG2=
set _INP_OP=
set _RET_NUM=
set _OUT_DP=
set _OUT_NEG=
set _INP_EXP_PAR=0
set _INP_EXP_DIV=0
set "_INP_NUM1=%~1"
set "_INP_NUM2=%~3"
set "_INP_OP=%~2"
if /i "%~2"=="*" (
set _INP_OP=x
)
if /i "%~2"=="%%" (
set _INP_OP=m
)
rem Default number of digits for division
set _DIV_DP=10
rem ***** Start Input validation *****
for %%z in ("/" "y") do (
if /i "%~2"=="%%~z" if not "%~4"=="" (
for /f "delims=0123456789 tokens=1*" %%a in ("A0%~4") do (
if "%%b"=="" (
for /f "tokens=1* delims=0" %%c in ("A0%~4") do (
if "%%d"=="" (
set _DIV_DP=0
) else set _DIV_DP=%%d
)
) else (
1>&2 Echo ERROR: "%~4" not detected as a valid number of decimal places
goto :eof
)
)
shift /4
)
)
if not "%~4"=="" (
1>&2 echo ERROR: Too many arguments: "%~4"
goto :eof
)
if not defined _INP_NUM1 (
1>&2 echo ERROR: Invalid Input: "!_INP_NUM1!"
goto :eof
)
if not defined _INP_NUM2 (
1>&2 echo ERROR: Invalid Input: "!_INP_NUM2!"
goto :eof
)
if not defined _INP_OP (
1>&2 echo ERROR: Invalid Operator: "!_INP_OP!"
goto :eof
)
if not "!_INP_OP:~1!"=="" (
1>&2 echo ERROR: Invalid Operator: "!_INP_OP!"
goto :eof
)
rem **** check for brackets on base exponent ****
if /i "!_INP_OP!"=="Y" (
for /f "tokens=1,2* delims=[]" %%a in ("A!_INP_NUM1!A]") do (
if "%%a%%c"=="AA]" (
set _INP_EXP_PAR=1
set _INP_NUM1=!_INP_NUM1:[=!
set _INP_NUM1=!_INP_NUM1:]=!
)
)
)
rem ***** / ***** Start Negitive input ***** \ *****
for %%a in (1 2) do (
if "!_INP_NUM%%a:~0,1!"=="-" if not "!_INP_NUM%%a:~1!"=="" (
set _INP_NUM%%a=!_INP_NUM%%a:~1!
set _INP_NEG%%a=-
) else (
1>&2 echo ERROR: Invalid input: "!_INP_NUM%%a!"
goto :eof
)
)
if not defined _INPUT_NEG1 set _INP_EXP_PAR=0
rem ***** \ ***** End Negitive input ***** / *****
rem ****** Bad characters ******
for /f "tokens=1* delims=0123456789." %%a in ("A0!_INP_NUM1!!_INP_NUM2!") do (
if not "%%b"=="" (
1>&2 echo ERROR: Invalid input: "!_INP_NUM1!" **OR** "!_INP_NUM2!"
goto :eof
)
)
rem ***** Fractional exponenets aren't supported ******
if /i "!_INP_OP!"=="y" (
for /f "tokens=1,2* delims=." %%a in ("0.!_INP_NUM1!!_INP_NUM2!") do (
if not "%%c"=="" (
1>&2 echo ERROR: Fractional exponents are not supported
goto :eof
)
)
)
for %%a in (1 2) do (
for /f "tokens=1-3 delims=." %%b in ("0!_INP_NUM%%a!0") do (
if not "%%d"=="" (
1>&2 echo ERROR: Invalid input: "!_INP_NUM%%a!"
goto :eof
)
)
)
for /f "tokens=1* delims=/Xx+-mMYy" %%a in ("A+!_INP_OP!") do (
if not "%%b"=="" (
1>&2 echo ERROR: Invalid operator: "!_INP_OP!"
goto :eof
)
)
rem ***** End input validation *****
rem ***** Start Remove leading zero's / Return for zero sums *****
for %%a in (1 2) do (
for /f "tokens=1* delims=0" %%b in ("A0!_INP_NUM%%a!") do (
if "%%c"=="" (
if /i "!_INP_OP!"=="x" echo 0
if "!_INP_OP!"=="/" (
if %%a==2 (
1>&2 Echo ERROR: Divide by zero
goto :eof
) else echo 0
) else if /i "!_INP_OP!"=="m" (
if %%a==2 (
1>&2 Echo ERROR: Divide by zero
goto :eof
) else echo 0
) else if "!_INP_OP!"=="-" (
if %%a==1 (
if defined _INP_NEG2 (
echo !_INP_NUM2!
) else echo -!_INP_NUM2!
) else (
echo !_INP_NEG1!!_INP_NUM1!
)
) else if "!_INP_OP!"=="+" (
if %%a==1 (
echo !_INP_NEG2!!_INP_NUM2!
) else echo !_INP_NEG1!!_INP_NUM1!
) else if /i "!_INP_OP!"=="y" (
if "%%a"=="1" (
if "!_INP_NEG2!"=="-" (
1>&2 echo ERROR: Negative exponents of zero are undefined.
) else (
echo 0
)
) else (
if "!_INP_EXP_PAR!"=="1" (
echo 1
) else (
echo !_INP_NEG1!1
)
)
)
goto :eof
) else set _INP_NUM%%a=%%c
)
)
rem ***** End Remove leading zero's / Return for zero sums *****
rem ***** Start Floating point normalisation *****
for %%a in (1 2) do (
if "!_INP_NUM%%a:~0,1!"=="." set _INP_NUM%%a=0!_INP_NUM%%a!
if "!_INP_NUM%%a:~-1!"=="." set _INP_NUM%%a=!_INP_NUM%%a!0
for /l %%b in (0 1 9) do set _INP_NUM%%a=!_INP_NUM%%a:%%b=%%b !
for %%c in (!_INP_NUM%%a!) do set /a _INP_LEN%%a+=1
set _INP_NUM%%a=!_INP_NUM%%a: =!
if "!_INP_NUM%%a!"=="!_INP_NUM%%a:.=!" (
set _INP_DP%%a=0
) else (
for /l %%d in (!_INP_LEN%%a! -1 1) do (
if not defined _INP_DP%%a if "!_INP_NUM%%a:~%%d,1!"=="." (
set /a _INP_DP%%a=!_INP_LEN%%a! - %%d
)
)
)
set _INP_NUM%%a=!_INP_NUM%%a:.=!
)
if !_INP_DP1! gtr !_INP_DP2! (
set /a _OUT_DP=_INP_DP1 - 1
) else set /a _OUT_DP=_INP_DP2 - 1
for /l %%a in (!_INP_DP1! 1 !_OUT_DP!) do set _INP_NUM1=!_INP_NUM1!0
for /l %%a in (!_INP_DP2! 1 !_OUT_DP!) do set _INP_NUM2=!_INP_NUM2!0
rem ***** End Floating point normalisation *****
rem ***** Start Negitive output checking *****
if /i "!_INP_OP!"=="x" (
if "!_INP_NEG1!!_INP_NEG2!"=="-" set _OUT_NEG=-
) else if "!_INP_OP!"=="+" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" set _OUT_NEG=-
if defined _INP_NEG2 if not defined _INP_NEG1 (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
set _OUT_NEG=-
)
set _INP_OP=-
)
if defined _INP_NEG1 if not defined _INP_NEG2 (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
) else if "!_GTR_RES!"=="1" set _OUT_NEG=-
set _INP_OP=-
)
) else if "!_INP_OP!"=="-" (
if "!_INP_NEG1!!_INP_NEG2!"=="" (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
set _OUT_NEG=-
)
)
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
call :isgreater !_INP_NUM1! !_INP_NUM2!
if "!_GTR_RES!"=="3" (
set _INP_NUM1=%_INP_NUM2%
set _INP_NUM2=%_INP_NUM1%
) else if "!_GTR_RES!"=="1" set _OUT_NEG=-
)
if defined _INP_NEG2 if not defined _INP_NEG1 set _INP_OP=+
if defined _INP_NEG1 if not defined _INP_NEG2 (
set _OUT_NEG=-
set _INP_OP=+
)
) else if "!_INP_OP!"=="/" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" set _OUT_NEG=
if "!_INP_NEG1!!_INP_NEG2!"=="-" set _OUT_NEG=-
) else if /i "!_INP_OP!"=="M" (
if defined _INP_NEG1 set _OUT_NEG=-
) else if /i "!_INP_OP!"=="Y" (
if "!_INP_EXP_PAR!"=="0" (
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
set _OUT_NEG=-
set _INP_EXP_DIV=1
) else if "!_INP_NEG2!"=="-" (
set _INP_EXP_DIV=1
) else if "!_INP_NEG1!"=="-" (
set _OUT_NEG=-
)
) else (
if "!_INP_NEG1!!_INP_NEG2!"=="--" (
for %%z in (1 3 5 7 9) do (
if "!_INP_NUM2:~-1!"=="%%z" set _OUT_NEG=-
)
set _INP_EXP_DIV=1
) else if "!_INP_NEG2!"=="-" (
set _OUT_NEG=-
set _INP_EXP_DIV=1
) else if "!_INP_NEG1!"=="-" (
for %%z in (1 3 5 7 9) do (
if "!_INP_NUM2:~-1!"=="%%z" set _OUT_NEG=-
)
)
)
)
rem ***** End Negitive output checking *****
Rem Main calling routines
if "!_INP_OP!"=="-" (
call :subtract %_INP_NUM1% %_INP_NUM2%
) else if "!_INP_OP!"=="+" (
call :add %_INP_NUM1% %_INP_NUM2%
) else if /i "!_INP_OP!"=="X" (
set /a _OUT_DP=^(_OUT_DP * 2^) + 1
call :multiply %_INP_NUM1% %_INP_NUM2%
) else if /i "!_INP_OP!"=="m" (
call :divide %_INP_NUM1% %_INP_NUM2% 0 m
) else if "!_INP_OP!"=="/" (
call :divide %_INP_NUM1% %_INP_NUM2% %_DIV_DP%
set /a _OUT_DP=_DIV_DP - 1
) else if /i "!_INP_OP!"=="Y" (
call :EXPONENT !_INP_NUM1! !_INP_NUM2!
if "!_INP_EXP_DIV!"=="1" (
call :DIVIDE 1 !_RET_NUM! !_DIV_DP!
set /a _OUT_DP=_DIV_DP - 1
)
) else (
1>&2 echo ERROR: Unknown operator.
goto :eof
)
rem finishing up.....
if not defined _OUT_DP (
set _OUT_DP=0
) else set /a _OUT_DP+=1
if not "!_OUT_DP!"=="0" (
for /l %%a in (1 1 !_OUT_DP!) do if "!_RET_NUM:~%_OUT_DP%!"=="" set _RET_NUM=0!_RET_NUM!
set _RET_NUM=!_RET_NUM:~0^,-%_OUT_DP%!.!_RET_NUM:~-%_OUT_DP%!
for /l %%a in (!_OUT_DP! -1 1) do (
if "!_RET_NUM:~-1!"=="0" set _RET_NUM=!_RET_NUM:~0^,-1!
if "!_RET_NUM:~-1!"=="." set _RET_NUM=!_RET_NUM:~0^,-1!
)
)
for /f "tokens=1* delims=0" %%a in ("A0!_RET_NUM!") do (
if "%%b"=="" (
set _RET_NUM=0
) else set _RET_NUM=%%b
)
if "!_RET_NUM:~0,1!"=="." set _RET_NUM=0!_RET_NUM!
IF NOT DEFINED _RET_NUM SET _RET_NUM=0
echo %_OUT_NEG%%_RET_NUM%
goto :eof
rem ***********************************************************************
rem ****************************** Subroutines ****************************
rem ***********************************************************************
:SUBTRACT
set _SUB_NUM1=%~1
set _SUB_NUM2=%~2
for %%a in (CHA RES LEN1 LEN2 CAR TOT) do set _SUB_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _SUB_NUM%%a=!_SUB_NUM%%a:%%b=%%b !
for %%c in (!_SUB_NUM%%a!) do set /a _SUB_LEN%%a+=1
set _SUB_NUM%%a=!_SUB_NUM%%a: =!
)
if !_SUB_LEN1! gtr !_SUB_LEN2! (
set /a _SUB_LEN=_SUB_LEN1 - 1
) else set /a _SUB_LEN=_SUB_LEN2 - 1
for /l %%b in (!_SUB_LEN1! 1 !_SUB_LEN!) do set _SUB_NUM1=0!_SUB_NUM1!
for /l %%b in (!_SUB_LEN2! 1 !_SUB_LEN!) do set _SUB_NUM2=0!_SUB_NUM2!
for /l %%a in (!_SUB_LEN! -1 0) do (
set /a _SUB_RES=!_SUB_NUM1:~%%a,1! - !_SUB_NUM2:~%%a,1!
if !_SUB_RES! lss 0 (
set _SUB_TAKE=
for /l %%b in (%%a -1 0) do if not defined _SUB_TAKE (
if not "%%b"=="%%a" (
if not "!_SUB_NUM1:~%%b,1!"=="0" (
set /a _SUB_CHA=!_SUB_NUM1:~%%b,1! - 1
set /a _SUB_TAKE=%%b + 1
for %%c in (!_SUB_TAKE!) do set _SUB_NUM1=!_SUB_NUM1:~0,%%b!!_SUB_CHA!!_SUB_NUM1:~%%c!
set /a _SUB_RES=1!_SUB_NUM1:~%%a,1! - !_SUB_NUM2:~%%a,1!
) else (
set /a _SUB_CHA=%%b + 1
for %%c in (!_SUB_CHA!) do set _SUB_NUM1=!_SUB_NUM1:~0,%%b!9!_SUB_NUM1:~%%c!
)
)
)
)
set _SUB_TOT=!_SUB_RES!!_SUB_TOT!
)
for /f "tokens=1* delims=0" %%a in ("A0!_SUB_TOT!") do set _SUB_TOT=%%b
if not defined _SUB_TOT set _SUB_TOT=0
set _RET_NUM=%_SUB_TOT%
goto :eof
:ADD
set _ADD_NUM1=%~1
set _ADD_NUM2=%~2
for %%a in (LEN1 LEN2 CAR TOT) do set _ADD_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _ADD_NUM%%a=!_ADD_NUM%%a:%%b=%%b !
for %%c in (!_ADD_NUM%%a!) do set /a _ADD_LEN%%a+=1
set _ADD_NUM%%a=!_ADD_NUM%%a: =!
)
if !_ADD_LEN1! gtr !_ADD_LEN2! (
set /a _ADD_LEN=_ADD_LEN1 - 1
) else set /a _ADD_LEN=_ADD_LEN2 - 1
for /l %%b in (!_ADD_LEN1! 1 !_ADD_LEN!) do set _ADD_NUM1=0!_ADD_NUM1!
for /l %%b in (!_ADD_LEN2! 1 !_ADD_LEN!) do set _ADD_NUM2=0!_ADD_NUM2!
for /l %%a in (!_ADD_LEN! -1 0) do (
set /a _ADD_CAR=_ADD_CAR + !_ADD_NUM1:~%%a,1! + !_ADD_NUM2:~%%a,1!
set _ADD_TOT=!_ADD_CAR:~-1!!_ADD_TOT!
set _ADD_CAR=!_ADD_CAR:~0,-1!
if not defined _ADD_CAR set _ADD_CAR=0
)
if !_ADD_CAR! gtr 0 set _ADD_TOT=!_ADD_CAR!!_ADD_TOT!
set _RET_NUM=%_ADD_TOT%
goto :eof
:MULTIPLY
set _MUL_NUM1=%1
set _MUL_NUM2=%2
for %%a in (CAR TOT) do set _MUL_%%a=0
for %%a in (X10 REV1 REV2) do set _MUL_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _MUL_NUM%%a=!_MUL_NUM%%a:%%b=%%b !
for %%c in (!_MUL_NUM%%a!) do set _MUL_REV%%a=%%c !_MUL_REV%%a!
)
for %%a in (!_MUL_REV1!) do (
set _MUL_ROW=!_MUL_X10!
for %%b in (!_MUL_REV2!) do (
set /a _MUL_CAR=^(%%a * %%b^) + _MUL_CAR
set _MUL_ROW=!_MUL_CAR:~-1!!_MUL_ROW!
set _MUL_CAR=!_MUL_CAR:~0,-1!
if not defined _MUL_CAR set _MUL_CAR=0
)
for /f "tokens=1* delims=0" %%c in ("A0!_MUL_CAR!!_MUL_ROW!") do (
if not "%%d"=="" (
call :ADD %%d !_MUL_TOT!
set _MUL_TOT=!_RET_NUM!
)
)
set _MUL_CAR=
set _MUL_X10=!_MUL_X10!0
)
set _RET_NUM=%_MUL_TOT%
goto :eof
:DIVIDE
for %%a in (LEN1 LEN2 X10 PAD) do set _DIV_%%a=
if /i not "%4"=="m" (
for /l %%a in (1 1 %3) do set _DIV_PAD=0!_DIV_PAD!
)
set _DIV_NUM1=%1!_DIV_PAD!
set _DIV_NUM2=%2
set _DIV_TOT=0
set _DIV_PRC=1
for %%a in (1 2) do (
for /f "tokens=1* delims=0" %%d in ("A0!_DIV_NUM%%a!") do set _DIV_NUM%%a=%%e
for /l %%b in (0 1 9) do set _DIV_NUM%%a=!_DIV_NUM%%a:%%b=%%b !
for %%c in (!_DIV_NUM%%a!) do set /a _DIV_LEN%%a+=1
set _DIV_NUM%%a=!_DIV_NUM%%a: =!
)
set /a _DIV_LEN1-=1
for /l %%a in (!_DIV_LEN2! 1 !_DIV_LEN1!) do set _DIV_X10=0!_DIV_X10!
:__DIVINL
call :ISGREATER %_DIV_NUM1% %_DIV_NUM2%%_DIV_X10%
if %_GTR_RES% leq 2 (
call :SUBTRACT %_DIV_NUM1% %_DIV_NUM2%%_DIV_X10%
set _DIV_NUM1=!_RET_NUM!
call :ADD %_DIV_TOT% 1%_DIV_X10%
set _DIV_TOT=!_RET_NUM!
) else if defined _DIV_X10 (
set _DIV_X10=!_DIV_X10:~1!
) else set _DIV_PRC=0
if "!_DIV_PRC!"=="1" goto :__DIVINL
if /i "%4"=="m" set _DIV_TOT=!_DIV_NUM1!
set _RET_NUM=%_DIV_TOT%
Goto :eof
:EXPONENT
set _EXP_SRL=
set _EXP_SQU=%2
set _EXP_TOT=%1
set _EXP_PRC=1
:__EXINL
call :DIVIDE !_EXP_SQU!0 2 0
set _EXP_SQU=%_RET_NUM%
if "%_EXP_SQU:~-1%"=="5" (
set _EXP_SRL=%_EXP_SRL% %_EXP_TOT%
)
set _EXP_SQU=%_EXP_SQU:~0,-1%
if "%_EXP_SQU%"=="" (
set _EXP_PRC=0
) else (
call :MULTIPLY %_EXP_TOT% %_EXP_TOT%
set _EXP_TOT=!_RET_NUM!
if "%_EXP_SQU%"=="3" (
set _EXP_SRL=!_EXP_SRL! !_EXP_TOT!
set _EXP_SQU=2
)
if "!_EXP_SQU!"=="2" (
call :MULTIPLY !_EXP_TOT! !_EXP_TOT!
set _EXP_TOT=!_RET_NUM!
for %%z in (!_EXP_SRL!) do (
call :MULTIPLY !_EXP_TOT! %%z
set _EXP_TOT=!_RET_NUM!
)
set _EXP_PRC=0
)
if "!_EXP_SQU!"=="1" (
set _EXP_PRC=0
)
)
if "!_EXP_PRC!"=="1" goto __EXINL
set _RET_NUM=!_EXP_TOT!
goto :eof
:ISGREATER
set _GTR_RES=
for /f "tokens=1* delims=0" %%a in ("A0%~1") do (
if "%%b"=="" (
set _GTR_NUM1=0
) else set _GTR_NUM1=%%b
)
for /f "tokens=1* delims=0" %%a in ("A0%~2") do (
if "%%b"=="" (
set _GTR_NUM2=0
) else set _GTR_NUM2=%%b
)
for %%a in (lEN1 lEN2) do set _GTR_%%a=
for %%a in (1 2) do (
for /l %%b in (0 1 9) do set _GTR_NUM%%a=!_GTR_NUM%%a:%%b=%%b !
for %%c in (!_GTR_NUM%%a!) do set /a _GTR_lEN%%a+=1
set _GTR_NUM%%a=!_GTR_NUM%%a: =!
)
if !_GTR_lEN1! gtr !_GTR_lEN2! (
set _GTR_RES=1
) else if !_GTR_lEN2! gtr !_GTR_lEN1! (
set _GTR_RES=3
) else (
set /a _GTR_lEN1-=1
for /l %%a in (0 1 !_GTR_lEN1!) do (
if not defined _GTR_RES (
if !_GTR_NUM1:~%%a^,1! gtr !_GTR_NUM2:~%%a^,1! set _GTR_RES=1
if !_GTR_NUM2:~%%a^,1! gtr !_GTR_NUM1:~%%a^,1! set _GTR_RES=3
)
)
)
if not defined _GTR_RES set _GTR_RES=2
goto :eof