Ya hemos visto que operar con decimales en Bash no es imposible, aunque es farragoso. Ahora veremos que pasa lo mismo para comparar decimales. Pero lo explico y dejo una función para que quien tenga que comparar, la copie en su script.

Primero comprobaremos si le hemos pasado bien los parámetros $1 y $2 a la función. Comprobamos si existen y tienen contenido. Si esto ocurre, comprobaremos que realmente son números que opcionalmente tienen un punto.

En caso de que sólo hubiera una variable numérica, se devuelve esa, ya que esa será la mayor.

Si las variables no fueran numéricas, se devuelve -1 de error.

Si ambas variables son nuḿéricas, se dividen en la parte entera y la parte decimal. Es decir, se extrae la subcadena desde el inicio hasta el punto, que es la parte entera, y la subcadena desde el punto hasta el fina, que es la parte decimal.

Comparamos las partes enteras. Si las partes enteras son distintas, el número mayor es el que tenga la parte entera mayor.

En caso de que las partes enteras sean iguales, seguimos haciendo comprobaciones:

Como recortamos subcadenas, igualamos su longitud con ceros al final de la subcadena más corta. Para que 0.02 no de mayor que 0.1.

Una vez que sabemos que la función ha recibido dos variables, que estas son numéricas con o sin punto, que hayamos separado la parte entera y la decimal, que las partes enteras son iguales y que las partes decimales tienen los mismos caracteres, comparamos los decimales.

Y devolvemos el parámetro cuya parte decimal sea mayor.

En caso de que la parte entera sea igual y la parte decimal sea igual tamibén, es que los dos números son iguales. Así que nos da igual cuál devolver. Devolveremos $1.

Y aquí el script con comentarios porque la función es un poco liosa:

<

[code]#!/bin/bash

function cualesmayor()
{
# Función que recibe dos parámetros con números decimales o no
# y devuelve el mayor de los dos

# Comprobamos que recibimos los dos parámetros,
# si recibimos solo uno, devolvemos ese

if [ "$1" ] && [ "$2" ]
then
# Existen ambas variables, por lo que podemos compararlas
# Comprobamos si ambos parámetros están formados únicamente
# por números y un único .

caracteresvalidos='^[0-9]+([.][0-9]+)?$'

if [[ $1 =~ $caracteresvalidos ]] && [[ $2 =~ $caracteresvalidos ]]
then
# Ambos son numéricos. Por lo que separaremos
# en la parte entera y la parte decimal

# Dónde está el punto. Si no hubiera punto, la posición es 0
let posicionpunto1=$(expr index $1 ".")
let posicionpunto2=$(expr index $2 ".")

# Extraemos las partes enteras.
if [ $posicionpunto1 -lt 0 ]
then
let parteentera1=$1
else
let numerodigitosparteentera1=$posicionpunto1-1
let parteentera1=${1:0:$numerodigitosparteentera1}
partedecimal1=${1:$posicionpunto1}

let numerodigitosparteentera2=$posicionpunto2-1
let parteentera2=${2:0:$numerodigitosparteentera2}
partedecimal2=${2:$posicionpunto2}

# Comprobamos las partes enteras

if [ $parteentera1 -gt $parteentera2 ]
then
echo $1
elif [ $parteentera1 -lt $parteentera2 ]
then
echo $2
else

# Ambas partes enteras son iguales
# Comprobamos las partes decimales
# Primero igualamos con ceros al final
# la longitud de las cadenas

tamdecimales1=${#partedecimal1}
tamdecimales2=${#partedecimal2}

if [ $tamdecimales1 -gt $tamdecimales2 ]
then
let diferencia=$tamdecimales1-$tamdecimales2
for i in $(seq 1 $diferencia)
do
partedecimal2=$partedecimal2"0"
done

elif [ $tamdecimales1 -lt $tamdecimales2 ]
then
let diferencia=$tamdecimales2-$tamdecimales1
for i in $(seq 1 $diferencia)
do
partedecimal1=$partedecimal1"0"
done
fi

if [ $partedecimal1 -gt $partedecimal2 ]
then
echo $1
elif [ $partedecimal1 -lt $partedecimal2 ]
then
echo $partedecimal2
else
# Ambas partes enteras son iguales
# Ambas partes decimales son iguales
# Ambos números son iguales
# Devolvemos el primero
echo $1
fi
fi

fi
else
echo -1
fi

else
if [ "$1" ] && [ ! "$2" ]
then
# $1 existe y no está vacío y $2 no existe o está vacío.
# Lo contrario nunca ocurrirá, ya que sin $1 no puede haber $2
echo $1
else
# Si llegamos aquí es porque no existe $1
echo -1
fi

fi
}

let operador1=3
let operador2=2

let operador3=5
let operador4=1

division1=$(echo "scale=4; $operador1/$operador2" | bc)
division2=$(echo "scale=4; $operador3/$operador4" | bc)

mayor=$(cualesmayor $division1 $division2)

echo "El primer resultado es "$division1" y el segundo resultado, "$division2". El mayor es "$mayor[code]
Publicado en Programación
Jueves, 01 Noviembre 2018 21:09

División con decimales en Bash

Para hacer operaciones sencillas en Bash podemos usar let, pero únicamente operaciones muy sencillas. Veamos un ejemplo:

#!/bin/bash

let operador1=3
let operador2=2

let suma=$operador1+$operador2
let resta=$operador1-$operador2
let multiplicacion=$operador1*$operador2
let division=$operador1/$operador2
let modulo=$operador1%$operador2


echo "La suma de "$operador1" + "$operador2" es "$suma
echo "La diferencia de "$operador1" + "$operador2" es "$resta
echo "El producto de "$operador1" x "$operador2" es "$multiplicacion
echo "El cociente de "$operador1" / "$operador2" es "$division
echo "El resto de "$operador1" / "$operador2" es "$modulo

 

Al ejecutarlo nos da este resultado:

La suma de 3 + 2 es 5
La diferencia de 3 + 2 es 1
El producto de 3 + 2 es 6
El cociente de 3 / 2 es 1
El resto de 3 / 2 es 1

Ufffff... ¡Pi es 3 exactamente!

No, no, que no te de un infarto, que pi no es 3. Y en Bash podemos calcularlo sin estos sobresaltos. Aunque no lo haremos con let, sino con bc.

De hecho, podemos indicar cuántos decimales queremos a través de scale. Veamos una aproximación a pi:

echo "scale=2; 355/113" | bc
3.14

Y con cuatro decimales:

echo "scale=4; 355/113" | bc
3.1415

Y con seis decimales:

echo "scale=6; 355/113" | bc
3.141592

Como se puede comprobar, esta división se aproxima a pi, pero el binomio bc/scale no redondean, únicamente cortan la muestra de decimales. Pero al menos muestran decimales, que let no lo hace.

Visto esto, modificamos el script del ejemplo:

#!/bin/bash

let operador1=3
let operador2=2

let suma=$operador1+$operador2
let resta=$operador1-$operador2
let multiplicacion=$operador1*$operador2
division=$(echo "scale=2; $operador1/$operador2" | bc)
let modulo=$operador1%$operador2

echo "La suma de "$operador1" + "$operador2" es "$suma
echo "La diferencia de "$operador1" + "$operador2" es "$resta
echo "El producto de "$operador1" x "$operador2" es "$multiplicacion
echo "El cociente de "$operador1" / "$operador2" es "$division
echo "El resto de "$operador1" / "$operador2" es "$modulo

Nótese que he quitado el let a la hora de definir la variable $division. Al ser decimal no lo acepta let.

El resultado que nos devuelve el script:

La suma de 3 + 2 es 5
La diferencia de 3 + 2 es 1
El producto de 3 x 2 es 6
El cociente de 3 / 2 es 1.50
El resto de 3 / 2 es 1

Esto ya es más bonito. Si decimos que pi es 3 exactamente que sea para llamar la atención, como el Profesor Frink, no porque nuestro script no sepa calcular con decimales.

 

 

 

Publicado en Programación

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí