Oct 14, 2013

Function: LargeInt_sub

Subtracts decimal numbers, handles signed input properly (unlike "raw" LargeInt_add, which does not check input at all, and has to receive unsigned integers). As you can see, it involves scripts I had written earlier, hence it seems a bit long.
@echo off
:loop
echo.
echo  give two big integers to be subtracted : 
set/p first=give first number : 
set/p second=give second number : 
echo.
call:LargeInt_sub first second third
if "%errorlevel%"=="0" (echo  ^(%first%^) - ^(%second%^) = ^(%third%^))
if "%errorlevel%"=="1" (echo  Too few parameters.)
if "%errorlevel%"=="2" (echo  Invalid input.)
goto loop
:LargeInt_sub
setlocal
set v0=%% %1 %%
set v0=%v0: =%
call set left=%v0%
set v0=%% %2 %%
set v0=%v0: =%
call set right=%v0%
if defined left (if defined right (goto lrgintsub))
set exitcode=1
goto lrgintsub_endproc
:negate
set var=%% %1 %%
set var=%var: =%
call set var=%var%
if "%var%"=="0" (
 :negate_
 set var=
 exit/b0
) else (
 if not "%var:~0,1%"=="-" (
  set %1=-%var%
 ) else (
  set var=%var:~1%
 )
 goto negate_
)
:lrgintsub
set sides_xchged=false
set left_IsNegative=false
set right_IsNegative=false
call:IsInteger left||endlocal&&exit/b2
call:IsInteger right||endlocal&&exit/b2
if "%left:~0,1%"=="-" (
 set left_IsNegative=true
 set left=%left:~1%
)
if "%right:~0,1%"=="-" (
 set right_IsNegative=true
 set right=%right:~1%
)
call:LargeInt_cmp left right
::exchange left with right if right is "longer" than left for the subtraction to process properly
if "%errorlevel%"=="2" (set right=%left%&set left=%right%&set left_IsNegative=%right_IsNegative%&set right_IsNegative=%left_IsNegative%&set sides_xchged=true)
if "%left_IsNegative%"=="false" (
 if "%right_IsNegative%"=="false" (
  ::left-right
  call:lrgintsub_l dummy dummy outvar
  if "%sides_xchged%"=="true" (call:negate outvar)
 )
)
if "%left_IsNegative%"=="true" (
 if "%right_IsNegative%"=="true" (
  ::-left-(-right)=right-left
  call:lrgintsub_l dummy dummy outvar
  if "%sides_xchged%"=="false" (call:negate outvar)
 )
)
if "%left_IsNegative%"=="true" (
 if "%right_IsNegative%"=="false" (
  ::-left-right=-(left+right)
  call:LargeInt_add left right outvar
  if "%sides_xchged%"=="false" (call:negate outvar)
 )
)
if "%left_IsNegative%"=="false" (
 if "%right_IsNegative%"=="true" (
  ::left-(-right)=left+right
  call:LargeInt_add left right outvar
  if "%sides_xchged%"=="true" (call:negate outvar)
 )
)
endlocal&set %3=%outvar%&exit/b%errorlevel%
:lrgintsub_l
set buff=
set lastchar_l=
set lastchar_r=
if defined left (set lastchar_l=%left:~-1%)
if defined right (set lastchar_r=%right:~-1%) else (set lastchar_r=0)
if %lastchar_r% GTR %lastchar_l% (call:lrgintsub_withborrow) else (call:lrgintsub_withoutborrow)
if defined left (set left=%left:~0,-1%)
if defined right (set right=%right:~0,-1%)
if not defined left (if not defined right (goto lrgintsub_opsucc))
goto lrgintsub_l
:lrgintsub_opsucc
set exitcode=0
:lrgintsub_endproc
if "%outvar:~0,1%"=="0" (if not "%outvar:~1%"=="" (set outvar=%outvar:~1%&goto lrgintsub_endproc))
endlocal&set %3=%outvar%&exit/b%exitcode%
:handle_borrow
set/a slider+=1
set left_tmp=%left:~-1%%left_tmp%
set left=%left:~0,-1%
if "%left:~-1,1%"=="0" (goto handle_borrow)
set left_tmp=%left_tmp:0=9%
set/a current_pos=%left:~-1,1%-1
set left_tmp=%current_pos%%left_tmp%&set/a slider+=1
set left=%left:~0,-1%
set left=%left%%left_tmp%
set slider=&set left_tmp=&set left_tmp0=&set current_pos=
exit/b0
:lrgintsub_withborrow
call:handle_borrow
set/a lastchar_l+=10
:lrgintsub_withoutborrow
set/a buff=%lastchar_l%-%lastchar_r%
set outvar=%buff%%outvar%
exit/b0
:LargeInt_cmp
::returns
::
:: ERRORLEVEL
:: 0 = left is greater
:: 1 = equal
:: 2 = right is greater
:: 3 = invalid input
::
setlocal
set v0=%% %1 %%
set v0=%v0: =%
call set left=%v0%
set v0=%% %2 %%
set v0=%v0: =%
call set right=%v0%
if not defined left (endlocal&&exit/b3)
if not defined right (endlocal&&exit/b3)
set left_IsNegative=false
set right_IsNegative=false
if "%left:~0,1%"=="-" (set left_IsNegative=true)
if "%right:~0,1%"=="-" (set right_IsNegative=true)
set cond_gtr=GTR
set cond_lss=LSS
if "%left_IsNegative%"=="true" (
 if "%right_IsNegative%"=="false" (
  goto right_is_greater
 )
)
if "%left_IsNegative%"=="false" (
 if "%right_IsNegative%"=="true" (
  goto left_is_greater
 )
)
if "%left_IsNegative%"=="true" (
 if "%right_IsNegative%"=="true" (
  set cond_gtr=LSS
  set cond_lss=GTR
 )
)
call:strlen %left%
set sizeof_left=%errorlevel%
call:strlen %right%
set sizeof_right=%errorlevel%
if %sizeof_left% %cond_gtr% %sizeof_right% (
 :left_is_greater
 endlocal&exit/b0
)
if %sizeof_left% %cond_lss% %sizeof_right% (
 :right_is_greater
 endlocal&exit/b2
)
:lrgintcmp_l
set left_tmp=%left:~0,1%
set right_tmp=%right:~0,1%
set left=%left:~1%
set right=%right:~1%
if %left_tmp% %cond_gtr% %right_tmp% (goto left_is_greater)
if %right_tmp% %cond_gtr% %left_tmp% (goto right_is_greater)
if defined left (goto lrgintcmp_l)
endlocal&exit/b1
:strlen
setlocal
set param=%1
if not defined param (set length=0&goto strlen_end)
:strlen_0
set param=%param:~0,-1%
set/a length+=1
if defined param (goto strlen_0)
endlocal&exit/b%length%

:IsInteger
call:IsHex %1 10&&exit/b0||exit/b1
:IsHex
setlocal
set var=%% %1 %%
set var=%var: =%
call set var=%var%
if "%2"=="10" (if "%var:~0,1%"=="-" (set var=%var:~1%)) else (if "%var:~0,2%"=="0x" (set var=%var:~2%))
set IsHex=0
set var=%var:0= %
set var=%var:1= %
set var=%var:2= %
set var=%var:3= %
set var=%var:4= %
set var=%var:5= %
set var=%var:6= %
set var=%var:7= %
set var=%var:8= %
set var=%var:9= %
if "%2"=="10" (goto ishex_)
set var=%var:A= %
set var=%var:B= %
set var=%var:C= %
set var=%var:D= %
set var=%var:E= %
set var=%var:F= %
:ishex_
set var=%var: =%
if defined var (set IsHex=1)
endlocal&exit/b%IsHex%

:LargeInt_add
setlocal
set v0=%% %1 %%
set v0=%v0: =%
call set left=%v0%
set v0=%% %2 %%
set v0=%v0: =%
call set right=%v0%
if defined left (if defined right (goto lrgintadd))
set exitcode=1
goto lrgintadd_endproc
:lrgintadd
set buff=
set lastchar_l=
set lastchar_r=
if defined left (set lastchar_l=%left:~-1%)
if defined right (set lastchar_r=%right:~-1%)
if defined carry (set/a buff+=%carry%&set carry=)
if defined lastchar_l (set/a buff+=%lastchar_l%)
if defined lastchar_r (set/a buff+=%lastchar_r%)
if %buff% GTR 9 (
 set outvar=%buff:~-1%%outvar%
 set carry=%buff:~0,1%
) else (
 set outvar=%buff%%outvar%
)
if defined left (set left=%left:~0,-1%)
if defined right (set right=%right:~0,-1%)
if not defined left (if not defined right (set outvar=%carry%%outvar%&goto lrgintadd_opsucc))
goto lrgintadd
:lrgintadd_opsucc
set exitcode=0
:lrgintadd_endproc
endlocal&set %3=%outvar%&exit/b%exitcode%

No comments:

Post a Comment