Comment comparer deux valeurs à virgule flottante en script shell
-
03-10-2019 - |
Question
Je devais faire une division dans le script shell et la meilleure façon était:
result1=`echo "scale=3; ($var1 / $total) * 100"| bc -l`
result2=`echo "scale=3; ($var2 / $total) * 100"| bc -l`
mais je veux comparer les valeurs de $result1
et $result2
Utilisation if test $result1 -lt $result2
ou if [ $result1 -gt $result2 ]
n'a pas fonctionné: (
Toute idée comment faire?
La solution
Vous pouvez comparer les nombres à virgule flottante en utilisant expr(1)
:
: nr@yorkie 3724 ; expr 3.1 '<' 3.3
1
: nr@yorkie 3725 ; expr 3.1 '<' 3.09
0
Vous pouvez également bc
faire les comparaisons ainsi que les calculs:
if [ "$(echo $result1 '<' $result2 | bc -l)" -eq 1 ];then ... fi
Enfin, ksh93 peut faire l'évaluation arithmétique $(($result1 < $result2))
avec des nombres à virgule flottante, bien que bash ne peut pas.
Autres conseils
Notez que tu dois être un peu prudents en traitant avec des nombres à virgule flottante et si vous testez pour l'égalité que vous voulez vraiment décider une certaine précision et comparer en utilisant cela. Quelque chose comme:
if (abs(x1-x2) < 0.0001) then equal # pseudo-code
la raison étant que les ordinateurs dont nous traitons avec des fractions binaires précision limitée pas vrai reals mathématiques. Limiter la précision en Colombie-Britannique à l'échelle = 3 aura cet effet.
Je voudrais aussi vous déconseillons d'essayer de faire ce genre de choses dans le script shell. Ce n'est pas que vous ne pouvez pas le faire, mais vous devrez bifurquer beaucoup de petites commandes de sous pour faire les bits difficiles et c'est lent à exécuter et généralement une douleur à écrire - vous passez la plupart de votre temps à essayer d'obtenir la coquille de faire ce que vous voulez plutôt que d'écrire le code que vous voulez vraiment. Laissez tomber dans un langage de script plus sophistiqué à la place; ma langue de choix est perl, mais il y a d'autres. comme ça ...
echo $var1 $var2 $total | perl -ne 'my ($var1, $var2, $tot) = split /\s+/; if ($var1/$tot == $var2/$tot) { print "equal\n"; }'
note également que vous divisant par la même valeur ($ au total dans votre question) si la comparaison entière peut se faire contre les numérateurs (var1 et var2) a fourni $ au total est positif
Publier une nouvelle réponse car je ne peux pas encore commenter ...
@Norman réponse de Ramsey n'est pas tout à fait exact:
-
expr
effectuera une comparaison entière ou une chaîne, pas une comparaison en virgule flottante.
Voici ce que la page de l'homme dit:{expr1 =,>,> =, <, <=,! =} Expr2
retour les résultats de comparaison de nombre entier si les deux arguments sont des nombres entiers; sinon, renvoie les résultats de comparaison de chaînes en utilisant la séquence de classement spécifique à la localisation.
(juste essayer
expr 8.9 '<' 10
et obtenir0
où il devrait être1
). -
bc
works grand, mais il est pas toujours installé.
Donc, une autre alternative est d'utiliser perl -e
:
-
perl -e 'print expression'
imprimera1
si l'expression est vraie et rien (chaîne vide) autrement.par exemple.
perl -e 'print 8.9 < 10'
-. estampes "1", alors que rien imprimeperl -e 'print 2>4'
-
Et quand il est utilisé dans l'instruction
if
:if [ $(perl -e "print $result1 < $result2") ];then ... fi