249 votes

Comment comparer deux nombres à virgule flottante dans Bash ?

J'essaie de comparer deux nombres à virgule flottante dans un script Bash script. J'ai deux variables, par exemple

let num1=3.17648e-22
let num2=1.5

Je voudrais maintenant faire une simple comparaison de ces deux chiffres :

st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
  echo -e "$num1 < $num2"
else
  echo -e "$num1 >= $num2"
fi

Malheureusement, j'ai quelques problèmes avec le traitement correct du num1 qui peut être du "e-format".

2 votes

Par "format électronique", j'entends la notation exponentielle (également appelée notation scientifique).

0 votes

324voto

Serge Stroobandt Points 525

Plus pratique

Cela peut être fait plus facilement en utilisant le contexte numérique de Bash :

if (( $(echo "$num1 > $num2" |bc -l) )); then
  …
fi

Explication

La tuyauterie à travers la commande de base de la calculatrice bc renvoie soit 1, soit 0.

L'option -l est équivalent à --mathlib ; il charge la bibliothèque mathématique standard.

Enfermer l'expression entière entre des doubles parenthèses (( )) traduira ces valeurs en vrai ou faux.

Veillez à ce que le bc Le logiciel de calculateur de base est installé.

Attention : La notation exponentielle doit être écrite comme suit *10^ ; non E , ni e .

Par exemple :

$ echo "1*10^3==1000" |bc
1

Considérant que

$ echo "1E3==1000" |bc
0

Stratégies pour y remédier bc limitation sont discuté ici .

116voto

alrusdi Points 286

Bash ne gère que les nombres entiers, mais vous pouvez utiliser la fonction bc comme suit :

$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1

Notez que le signe de l'exposant doit être en majuscule.

3 votes

Oui, mais pour contourner les calculs incorrects, il faut mettre le signe 'e' en majuscule dans la notation scientifique des nombres et utiliser l'option -l pour éviter de programmer des routines mathématiques prédéfinies.

2 votes

Tu devrais le préciser dans ta réponse, au lieu de poster une solution très similaire sans mentionner les différences importantes.

4 votes

Il ne s'agit pas d'un très similaire solution. La solution d'Alrusdi utilise la bc et c'est ce que je recommande à tout programmeur BASH. BASH est un langage sans typage. Oui, il peut faire de l'arithmétique entière, mais pour la virgule flottante, vous devez utiliser un outil externe. BC est le meilleur parce qu'il est fait pour cela.

34voto

ungalcrys Points 149

Vous pouvez utiliser AWK en combinaison avec une application Bash si l'état :

if awk "BEGIN {exit !($d1 >= $d2)}"; then
    echo "yes"
else
    echo "no"
fi

2 votes

L'utilisation d'awk est intéressante car elle permet de gérer les nombres à virgule flottante, mais je préfère personnellement le synthax. if (( $(echo $d1 $d2 | awk '{if ($1 > $2) print 1;}') )); then echo "yes"; else echo "no"; fi

2 votes

Cela ne fonctionne pas comme prévu. Awk sort avec un statut 0 quoi qu'il en soit. Remplacer print con exit et vous l'avez.

2 votes

@Otheus Vous devez le remplacer par exit ! sinon il renverrait l'inverse. J'ai modifié la réponse en conséquence.

31voto

anubhava Points 172509

Il est préférable d'utiliser AWK pour les mathématiques non entières. Vous pouvez utiliser cette fonction d'utilité de Bash :

numCompare() {
   awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}

Et l'appeler ainsi :

numCompare 5.65 3.14e-22
5.65 >= 3.14e-22

numCompare 5.65e-23 3.14e-22
5.65e-23 < 3.14e-22

numCompare 3.145678 3.145679
3.145678 < 3.145679

2 votes

J'aime cette réponse, les gens ont tendance à fuir awk, surtout les débutants, ils semblent penser que c'est plus difficile que ça ne l'est en réalité, je pense que les gens sont intimidés par les accolades et la syntaxe apparemment mixte du langage (à première vue). Et puisque awk est pratiquement garanti d'être présent sur le système cible, tout comme bc (je ne sais pas lequel, s'il y en a un, n'est jamais NON installé). J'adore les scripts bash, mais l'absence de virgule flottante, même pas de 2 décimales (je suppose que quelqu'un pourrait écrire un "faux" wrapper pour ça), c'est vraiment ennuyeux...

0 votes

Je suis d'accord, awk fournit à peu près tout ce que les shells purs ne peuvent pas faire.

2 votes

Utilisation awk y bc dans les scripts du shell est une pratique courante depuis les temps anciens, je dirais que certaines fonctionnalités n'ont jamais été ajoutées aux shells parce qu'elles sont disponibles dans awk, bc et d'autres outils Unix. Pas besoin de pureté dans les scripts du shell.

31voto

user Points 1438

Une solution purement Bash pour comparer des flottants sans notation exponentielle, ni zéros de tête ou de queue :

if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
  echo "${FOO} > ${BAR}";
else
  echo "${FOO} <= ${BAR}";
fi

L'ordre des opérateurs logiques questions . Les parties entières sont comparées comme des nombres et les parties fractionnaires sont intentionnellement comparées comme des chaînes de caractères. Les variables sont divisées en parties entières et fractionnaires à l'aide de la fonction cette méthode .

Il ne compare pas les flottants avec les entiers (sans point).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X