Mostrando entradas con la etiqueta Batch. Mostrar todas las entradas
Mostrando entradas con la etiqueta Batch. Mostrar todas las entradas

Multiplicación y división con decimales

Si bien ayer expuse un conversor de Hexadecimal a decimal, el objetivo final no es más que un conversor de Decimal a Hexadecimal.
Dicho objetivo no se nos plantea tan complicado usando cualquier lenguaje de programación, pero, como todos sabemos, Batch no es un lenguaje de programación y esto nos trae ciertos problemas, los más dignos de destacar creo que son la inexistencia de la función Len y la discapacidad de Batch frente a operaciones matemáticas con decimales.

Si señores, leen bien, batch es incapaz de sumar dos números decimales provocando el error tan conocido de: ' Falta Operador '.
Para solucionar esto, los programadores hemos creado códigos que se adaptan a la necesidad del proyecto final. E encontrado varios códigos en la red sobre Multiplicaciones y Divisiones con decimales en batch (que son operaciones necesarias para convertir números decimales a hexadecimales) pero como ninguno de ellos me acababa de convencer (o bien la lógica de programación era muy confusa, o simplemente no daba el resultado esperado, decidí crear mis dos propias funciones que pasaré a explicar a continuación:

Multiplicación con decimales



Se me pasó por la cabeza crear un code que cumpliera con la multiplicación con decimales en los 2 niveles (nivel 1: 2,12*2 nivel 2: 2,12*2,1) el caso es que tras pensar un rato no llegué a una conclusión lógica de como efectuar una operación de nivel 2 y como no era de vital necesidad para mi objetivo me decanté por multiplicaciones de nivel 1.

Teniendo como ejemplo: 2,20*6, el proceso empieza por separar las 2 partes de la variable con decimales a partir de la ',' (part1=2 part2=20. Esas dos partes se multiplican por el multiplicador (2*6 y 20*6).
A la segunda parte se le corre la coma según el número de decimales (en este caso 1,20), para ello hace falta separar la variable en dos partes mas (p1 y p2) donde la primera parte es la parte entera y la segunda la parte decimal.
Para finalizar se suma la parte 1 de la segunda separación (p1) a la parte 1 de la primera (parte1), dándonos como resultado 13,2.

División con Decimales



Para la división con decimales solo decir que el método me sorprendió y no es originalmente mío (lo encontré en la red no recuerdo donde...), simplemente intenté codearlo de una forma más clara y de acuerdo a mis necesidades.

El proceso es más sencillo y repetitivo, empezamos dividiendo el dividendo por el divisor y, como batch solo devuelve enteros, buscamos el resto. Con esta acción ya tenemos la parte entera, solo nos falta la decimal.

Para la parte decimal empezamos comprobando que el resto no sea 0, después de hacer eso solo nos encargamos de dividir el resto anterior (agregando un al final 0) para obtener el decimal y de buscar el MOD (resto) del resto anterior (agregando también un 0) para obtener el siguiente decimal, y así hasta que de 0.

Pueden hacer la comprobación con este mismo ejemplo: 1711*16 = 106,9375

Y para terminar por hoy (el convertidor decimal a hexadecimal otro día :p) dejo ambos códigos para análisis, recuerdo que pueden encontrarlos también en Bl4ck-P0rtal.org


Multiplicación.bat
@echo off
:: call :decimal_multi numero_decimal numero_entero
:: devuelve %multi%

:decimal_multi
setlocal
set num1=%1
set num2=%2

for /f "tokens=1,2 delims=." %%a in ("%num1%") do (
call :len %%b
set /a part1=%%a*%num2%
set /a part2=%%b*%num2%
)

call set p2=%%part2:~-%long%%%
set minus=%long%
call :len %part2%
set /a minus=%long%-%minus%
call set p1=%%part2:~0,%minus%%%

set /a suma=%p1%+%part1%
endlocal && set multi=%suma%.%p2% && goto :eof

:len
set len=%1
set long=0
:_loop
call set var=%%len:~%long%,1%%
if not defined var (goto :eof)
set /a long+=1
goto _loop


División.bat

@echo off
:: call :decimal_division dividendo divisor
:: devuelve: %division%

:decimal_division
setlocal
set dividendo=%1
set divisor=%2
set decimales=0

set /a "entero=%dividendo%/%divisor%"
set /a "resto0=%dividendo%%%%divisor%"

:div_decimal
if [!resto%decimales%!]==[0] goto div_fin
set /a sig=%decimales%+1
set /a decimal%decimales%=!resto%decimales%!0/%divisor%
set /a resto%sig%=!resto%decimales%!0%%%divisor%
set /a "decimales+=1"
goto div_decimal

:div_fin
for /l %%a in (0,1,%decimales%) do (set final=!final!!decimal%%a!)
endlocal && set division=%entero%.%final% && goto:eof

Hexadecimal To Decimal Converter

Como primer proyecto pensé en exponer algún que otro trabajo, pero como algunos me van a pegar si vuelvo a poner la v1 o la v2 del SNAKX, el juego en ActionScript o algún otro code que haya quedado en el olvido, prefiero presentar un sencillo trabajo en Batch.

La idea de realizar el code fue que se necesitaba un código para el S.C.O.T Team que consistiera en pasar valores decimales a Hexadecimales y como a mí me gusta ir al revés de la situación creé un code para pasar Hexadecimales a Decimales :P

Con el tiempo se van a ir dando cuenta que mi especialidad no es el diseño (es más, lo detesto y soy totalmente negado a ello...) así que mis programas consisten en una interfaz muy sencilla (o ninguna interfaz, como es el caso) y un código estructurado.



En este artículo voy a explicar el procedimiento que se sigue para pasar de un valor Hexadecimal a un valor Decimal.

Primeramente hace falta saber que un número Hexadecimal está en y un número Decimal en Base 10.

Entonces, primeramente necesitamos la longitud del texto, para ello llamamos a la función :Len, que nos retornará la longitud en la variable %long%.
A continuación separaremos cada digito para poder trabajar con él y lo guardaremos en una simulación de array que llamaremos digit_X (siendo X el valor numérico de la posición del array).
Aprovecharemos el mismo bucle para hacer la substitución de caracteres, siendo A=10 y F=16

Una vez finalizada la etapa de separación y substitución, nos introducimos en otro bucle (la razón de que no se haga todo en el mismo bucle es porque necesitamos todas las variables definidas para trabajar con ellas) en el cual aremos los cálculos apropiados.

La regla para convertir un valor hexadecimal a decimal dice que hemos de tomar los números de derecha a izquierda, multiplicarlos por su base elevada a n+1 y sumarlos.

Ejemplo con el valor '2A'

2(16^1)+A(16^0) = 2*16 + 10*1 = 32+10 = 42


Entonces hacemos exactamente eso en el último for, la única curiosidad es la función :Potencia que se encarga de multiplicar el número a su potencia

Syntaxis: call :potencia indice exponente


Finalmente mostramos el valor en hexadecimal y su conversión a decimal


A continuación os dejo el code para vuestra valoración:

@echo off
@title Hexadecimal To Decimal
SETLOCAL ENABLEDELAYEDEXPANSION
:ini
cls
set decimal=0
set /p "hexa=numero hexadecimal>>"
if not defined hexa goto ini
call :len %hexa%
set /a long+=1

for /l %%a in (1,1,%long%) do (
set digit_%%a=!hexa:~-%%a,1!
set cnt=9

for %%b in (A,B,C,D,E,F) do (
set /a cnt+=1
call set digit_%%a=!digit_%%a:%%b=%%cnt%%!)
)


for /l %%a in (1,1,%long%) do (
set /a exponente=%%a-1
call :potencia 16 !exponente!
set /a digit_%%a=!digit_%%a!*!potencia!
set /a decimal=!digit_%%a!+!decimal!
)

echo Hex: !hexa! -^> Dec: !decimal!
pause>nul
goto ini


:potencia
if %2==1 (set potencia=%1 & goto :eof)
if %2==0 (set potencia=1 & goto :eof)

set "potencia=%1"
for /l %%a in (2,1,%2) do (set /a potencia*=%1)
goto :eof



:len
set len=%1
set long=0
:_loop
call set var=%%len:~%long%,1%%
if not defined var (set /a long-=1 && goto :eof)
set /a long+=1
goto _loop