[BATCH]Suma y resta números de cualquier longitud

Iniciado por Binary_Death, 24 Julio 2012, 05:19 AM

0 Miembros y 1 Visitante están viendo este tema.

Binary_Death

Aquí dos funciones nuevas relacionadas con la suma y la resta. Las otras eran para decimales, estas son para saltarse el límite de 32 bits de precisión que tiene la cmd al operar.

Después, cuando haga funciones para división y multiplicación decimal y corrija todos los bugs de estas funciones, lo unificaré todo en una sola clase para poder trabajar en batch con cualquier número real, con todos los dígitos decimales que uno quiera.

Aquí vienen las funciones:


:_addx
setlocal enabledelayedexpansion
set "f_s=_%~1" & set "s_s=_%~2" & set "add_str="
set/a cnt=1,car=0
:__loop.a
set "n_1=!f_s:~-%cnt%,1!"
set "n_2=!s_s:~-%cnt%,1!"
if "%n_1%%n_2%" EQU "__" goto :_endadd
if "%n_1%" EQU "_" set/a n_1=0
if "%n_2%" EQU "_" set/a n_2=0
set/a add=%n_1%+%n_2%+%car%,car=0,cnt+=1
if %add% GEQ 10 (
set/a car=1
if "!f_s:~-%cnt%,1!!s_s:~-%cnt%,1!" NEQ "__" (
set "add=%add:~-1%"
))
set "add_str=%add%%add_str%"
goto :__loop.a
:_endadd
call :_filset "%add_str%" "add_str"
endlocal & set "%~3=%add_str%" & exit /b

:_subx
setlocal enabledelayedexpansion
if "%~1" EQU "%~2" set "sub_str=0" & goto :_endsub
call :_filset "%~1" "t_1" & call :_filset "%~2" "t_2"
call :_hst "%t_1%" "%t_2%"
if "%hst%" EQU "%t_2%" set "min=_%~2" & set "sbs=_%~1" & set "s_g=-"
if "%hst%" EQU "%t_1%" set "min=_%~1" & set "sbs=_%~2"
set "sub_str=" & set/a cnt=1,c_s=0,car=0
:__loop.b
set "n_1=!min:~-%cnt%,1!"
set "n_2=!sbs:~-%cnt%,1!"
if "%n_1%%n_2%" EQU "__" goto :_endsub
if "%n_2%" EQU "_" set/a n_2=0
if "%car%" EQU "1" set/a n_2+=1,car=0
if %n_1% LSS %n_2% set/a c_s=10,car=1
set/a sub=%n_1%-%n_2%+%c_s%
set "sub_str=%sub%%sub_str%"
set/a cnt+=1,c_s=0
goto :__loop.b
:_endsub
call :_filset "%sub_str%" "sub_str"
endlocal & set "%~3=%s_g%%sub_str%" & exit /b

:_filset
for /f "tokens=* delims=0" %%_ in ("%~1") do set "%~2=%%_"
if not defined %~2 set/a "%~2=0"
exit /b

:_hst
setlocal enabledelayedexpansion
call :_strlen "%~1" & set/a n[0]=!errorlevel!
call :_strlen "%~2" & set/a n[1]=!errorlevel!
if %n[0]% EQU %n[1]% set "s_0=%~1" & set "s_1=%~2" & goto :_endhst
set/a hst=0,nhst=1
if %n[1]% GTR !n[%hst%]! set/a hst=1,nhst=0
set/a l_0=!n[%hst%]!-!n[%nhst%]!
shift/0 & call set "s_0=%%~%hst%" & call set "s_1=%%~%nhst%"
for /l %%_ in (1,1,%l_0%) do call set "s_1=0!s_1!"
:_endhst
for /f %%_ in ('"(echo:%s_0%&echo:%s_1%)|sort"') do set "hst=%%_"
endlocal & set "hst=%hst%" & exit /b

:_strlen
setlocal
set/a cnt=0
for /f "tokens=* eol=" %%_ in (
'"cmd /u /c echo:%~1|more"'
) do set/a cnt+=1
endlocal & exit /b %cnt%


La sintaxis es:


call :_addx "sum1" "sum2" "variable_almacén"
call :_subx "min" "sbs" "variable_almacén"


Un saludo, y por favor, cualquier bug que encuentren díganmenlo, que así me ayudarán a mejorar la clase final ;)

PD: Devuelve también, en el caso de la resta, resultados negativos si el substraendo es mayor que el minuendo ;)

EDIT: Bug fixeado.

Un pequeño ejemplo de su uso:


@Echo Off
more/c<nul
echo:  125504500255796221456988250471037
echo:-        47662554011498822047690014
echo:-------------------------------------
call :_subx "125504500255796221456988250471037" "47662554011498822047690014" "rslt"
echo:  %rslt%
pause>nul & exit


Como podéis ver, estos números son imposibles de operar en batch, pero usando esta función es posible.

Con decimales y con capacidad para manejar números astronómicos, creo que ya no hay excusas para no hacer programas de matemáticas en batch.

BatchianoISpyxolo

Genial binary_death. Trataré de testearlo :)

Yo también estoy implementando el tipo de dato array-fake (unidimensional) aunque voy poquito a poco. Fake porque se basa simplemente en variables estáticas  ;D pero ya va tomando forma.

Hace años un compi mío que también estaba en IH, hizo que batch trabajara con decimales, pero no recuerdo cómo ni qué exactamente... a ver si encuentro el código... :)

A ver si hoy me pongo con el TAD array y lo posteo...

Salud3t3S
Puede que desees aprender a programar desde 0: www.espascal.es