2010-05-04 6 views
4

je devais faire une division dans le script shell et la meilleure façon était:Comment comparer deux valeurs à virgule flottante en script shell

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

En utilisant if test $result1 -lt $result2 ou if [ $result1 -gt $result2 ] ne fonctionne pas :(

Toute idée comment faire?

Répondre

6

Vous pouvez comparer floatin numéros g-point à l'aide expr(1):

: [email protected] 3724 ; expr 3.1 '<' 3.3 
1 
: [email protected] 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.

+0

'if [ "$ (echo $ resutl1 '>' result2 de $ | bc -l)" -eq 1], puis' travaille pour moi :) – Reem

0

Notez que vous devez être prudent lorsque vous manipulez des nombres à virgule flottante et si vous testez l'égalité, vous voulez vraiment choisir une certaine précision, puis comparer en utilisant cela. Quelque chose comme:

if (abs(x1-x2) < 0.0001) then equal # pseudo-code 

la raison étant que les ordinateurs que nous avons affaire avec des fractions binaires limitées précision pas vrai reals mathématiques. Limiter la précision en bc avec l'échelle = 3 aura cet effet.

Je vous déconseille également d'essayer de faire ce genre de choses dans un script shell. Ce n'est pas que vous ne pouvez pas le faire, mais vous aurez à débourser beaucoup de petites commandes secondaires pour faire les choses difficiles et c'est lent à exécuter et généralement une douleur à écrire - vous passez le plus clair de votre temps à essayer le shell faire ce que vous voulez plutôt que d'écrire le code que vous voulez vraiment. Déposez-vous plutôt dans un langage de script plus sophistiqué. ma langue de choix est perl mais il y en 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"; }' 

Notez également que vous êtes en divisant par la même valeur (total de $ dans votre question) si la comparaison entière peut être fait contre les numérateurs (var1 et var2) fourni $ total est positif

0

Publier une nouvelle réponse puisque je ne peux pas encore commenter ...

@Norman Ramsey's answer n'est pas tout à fait exact:

  • expr sera perfo rm une comparaison d'entier ou de chaîne, pas une comparaison à virgule flottante.
    Voici ce que la page de manuel dit:

    expr1 {=,>,> =, <, < = =!} Expr2

    Retour les résultats de comparaison entier si les deux arguments sont des entiers sinon, renvoie les résultats de comparaison de chaînes en utilisant la séquence de classement spécifique aux paramètres régionaux.

    (juste essayer expr 8.9 '<' 10 et obtenir 0 où il devrait être 1).

  • bc fonctionne très bien, mais il est pas toujours installé.


Donc, une autre alternative est d'utiliser perl -e:

  • perl -e 'print expression' imprimera 1 si l'expression est vraie et rien (chaîne vide) autrement.

    par exemple. perl -e 'print 8.9 < 10' - imprime "1", tandis que perl -e 'print 2>4' imprime rien.

  • Et quand il est utilisé dans if déclaration:

    if [ $(perl -e "print $result1 < $result2") ];then ... fi

Questions connexes