IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linux Discussion :

Comparaison de nombres flottants en shell


Sujet :

Linux

  1. #1
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut Comparaison de nombres flottants en shell
    Bonjour à tous...

    Voilà, je gère des numéros de versions d'une application.
    Au cours d'un lancement d'application, j'ai besoin de comparer le numéro actuelle de la version de l'appli avec le numéro de la version d'un client, enfin bref, je veux comparer en fait deux flottant vu que la version est de la forme: x.y (x et y étant des entiers).

    La comparaison doit se faire dans un script shell.

    Alors moi, je suis parti tête la première en programmant un truc du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if [ $VERSION_APPLI > $VERSION_CLIENT ]
    		then
    			echo "je fais le bon traitement ici"
    		fi
    Je teste mon programme avec VERSION_APPLI valant 3.1 et VERSION_CLIENT valant 4.0 (j'ai bien vérifié en faisant des echo) et le programme rentre quand même dans la conditionnelle or il ne devrait pas.
    J'ai cherché un peu à droite à gauche et j'ai vu que y'avait la notion de comparaison de chaine et de numérique.
    J'ai donc essayé en remplaçant le symbole '>' par '-gt' mais ça, ça marche que pour les entiers.
    Donc mon souci, comment faire pour que ça marche avec du flottant?

    J'ai bien eu une idée, c'est de multiplier les numéro de version et de comparer avec '-gt' mais ça marche pas non plus.

    Par exemple, si j'exécute:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    echo $(( $VERSION_APPLI*10 ))
    ça me retourne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ./shVoxDb: line 113: 3.1*10 : syntax error in expression (error token is ".1*10 ")
    comme si mon shell n'était pas capable de gérer les flottants... quelqu'un a une idée???
    Merci d'avance!

  2. #2
    Expert éminent sénior Avatar de frp31
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Juillet 2006
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2006
    Messages : 5 196
    Points : 12 262
    Points
    12 262
    Par défaut
    au pire tu peux utiliser BC pour les calculs un peu complexes

    en fait je crois même qu'il y a la fonction comparative pour flottants dans BC mais je suis pas sur à vérifier dans le man page.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Et en échappant <?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if [ $VERSION_APPLI \> $VERSION_CLIENT ]
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if [[ $VERSION_APPLI > $VERSION_CLIENT ]]
    Quel shell utilises-tu?

  4. #4
    Membre expérimenté
    Avatar de narmataru
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    1 548
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 548
    Points : 1 680
    Points
    1 680
    Par défaut
    Bonjour,
    pour les chiffres à virgule il faut utiliser la commande 'bc' :
    narma@linimi:~$ a=1.5
    narma@linimi:~$ b=1.6
    narma@linimi:~$ if [ $(echo " $a < $b" | bc) -eq 1 ]; then echo "ok"; fi
    ok
    narma@linimi:~$ b=1.49
    narma@linimi:~$ if [ $(echo " $a < $b" | bc) -eq 1 ]; then echo "ok"; fi
    narma@linimi:~$ b=1.3
    narma@linimi:~$ if [ $(echo " $a < $b" | bc) -eq 1 ]; then echo "ok"; fi
    narma@linimi:~$ a=1.001
    narma@linimi:~$ if [ $(echo " $a < $b" | bc) -eq 1 ]; then echo "ok"; fi
    ok

  5. #5
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut
    ripat>>
    J'utilise sh.
    Et apparemment, il ne peut vraiment pas prendre en compte les flottants à part sous forme de chaines, donc toutes comparaisons s'avèrera foireuse.

    La solution donnée plus haut convient, ça donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    COMP=$(echo "$VERSION_APPLI>$VERSION_CLIENT" | bc)
    		if [ $COMP -eq 1 ]
    		then
    			echo "mon traitement"
    		fi
    Donc merci beaucoup!
    Il me reste un problème par contre, c'est que ma version peut en fait avoir une lettre dedans, après la virgule, du genre 3.1a alors là, je vois pas comment faire.
    En fait, je ne sais pas comment fonctionne la comparaison de chaine, donc je ne vois pas pourquoi elle ne réussit pas dans le cas que j'ai décris dans mon premier post (3.1 et 4.0). Quelqu'un peut t'il m'expliquer comment ça marche quand on compare deux chaines bon, du point de vue égalité, je vois comment ça marche, mais du point de vue supérieur, inférieur à, quels critères sont utilisés?

    Merci d'avance

  6. #6
    Expert éminent sénior Avatar de frp31
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Juillet 2006
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2006
    Messages : 5 196
    Points : 12 262
    Points
    12 262
    Par défaut
    heu limiter la lecture à x.y ? pour éviter les lettres ? ok je sors

  7. #7
    Membre expérimenté
    Avatar de narmataru
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    1 548
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 548
    Points : 1 680
    Points
    1 680
    Par défaut
    Je pencherais plutot dans une découpe de chaine via awk/sed pour récupérer le numéro de version majeur, le mineur puis la lettre et ainsi tester ces valeurs une par une...

  8. #8
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut
    Citation Envoyé par narmataru
    Je pencherais plutot dans une découpe de chaine via awk/sed pour récupérer le numéro de version majeur, le mineur puis la lettre et ainsi tester ces valeurs une par une...
    Ouaip, je crois que je vais me lancer la-dedans, merci pour l'idée!

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Citation Envoyé par the_ionic
    ripat>>
    J'utilise sh.
    Et apparemment, il ne peut vraiment pas prendre en compte les flottants à part sous forme de chaines, donc toutes comparaisons s'avèrera foireuse.
    Bash dispose d'un opérateur de comparaison de chaînes.

    man bash ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
           chaîne_1 < chaîne_2
                  Vrai si chaîne_1 se trouve avant chaîne_2 dans l'ordre lexicographique de la localisation en cours.
           chaîne_1 > chaîne_2
                  Vrai si chaîne_1 se trouve après chaîne_2 dans l'ordre lexicographique de la localisation en cours.
    Il est donc tout à fait possible de comparer des chaînes comme
    1.25 1.30
    1.25 1.3
    1.2a 1.2c

    etc..


    Attention toutefois:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [[ "12.2a" > "12.25"  ]] && echo "plus grand"
    renvoie "plus grand"

  10. #10
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    je veux comparer en fait deux flottant vu que la version est de la forme: x.y (x et y étant des entiers).
    Attention, c'est une comparaison d'entier qu'il faut faire, la comparaison de flottant n'est pas exacte sur un shell ( à moins d'être sur du contraire). De plus pour ton problème, il suffit de découper comme on te l'a suggéré en majeur, mineur révision.

    Tu compare dans l'ordre et il ne devrait pas y avoir de souci.

  11. #11
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut
    ripat>>
    Ok, en fait tu m'avais donné la bonne solution dès le début (à part effectivement dans le cas que tu cites avec les lettres) mais je n'avais pas vu les doubles-crochets... pourquoi a t'on besoin de mettre [[ ]] au lieu de []?
    Par contre, je comprends dans ton exemple que la lettre doit être placé avant le chiffre dans l'alphabet mais en cherchant sur le net, je trouve pas une table qui me donne l'ordre lexicographique. Ok, c'est l'alphabet, mais pour moi, dans l'alphabet, y'avait que des lettres, alors les chiffres sont tous placés après, c'est ça?

    PRomu@ld>>
    Comme dit précédemment, je vais prendre ta solution, je vais me lancer la dedans ce matin car je ne m'y connais pas trop en awk/sed.

    Merci.

  12. #12
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut
    Oups, j'avais rajouté une grosse bêtise, désolé!

  13. #13
    Membre à l'essai
    Inscrit en
    Juin 2006
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 40
    Points : 20
    Points
    20
    Par défaut
    Je rajoute la solution me semble-t'il qui marche pour le problème au cas ou quelqu'un se trouve face au problème...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
     
    # Pour comparer les versions, il ne faut pas utiliser la comparaison lexicographique directement
    # car elle entraine des resultats faux dans certains cas
    # On sépare donc un numéro de version en trois - Le prefixe (nombre entier), le mineur (chiffre), et la release (lettre)
    # La variable COPY_SCRIPT indique si il est necessaire de copier les
    # scripts de l'application vers le client
     
    COPY_SCRIPT="0"
    VERSION_CLIENT=4.2
    VERSION_APPLI=4.1a
    SUFFIX_CLIENT=$(echo $VERSION_CLIENT | awk -F . '{ print $2 }')
    PREFIX_CLIENT=$(echo $VERSION_CLIENT | awk -F . '{ print $1 }')
    MINOR_CLIENT=$(echo $SUFFIX_CLIENT | sed -e 's/[a-z]//' ) 
    RELEASE_CLIENT=$(echo $SUFFIX_CLIENT | sed -e 's/[0-9]//' )
     
     
    SUFFIX_APPLI=$(echo $VERSION_APPLI | awk -F . '{ print $2 }')
    PREFIX_APPLI=$(echo $VERSION_APPLI | awk -F . '{ print $1 }')
    MINOR_APPLI=$(echo $SUFFIX_APPLI | sed -e 's/[a-z]//' ) 
    RELEASE_APPLI=$(echo $SUFFIX_APPLI | sed -e 's/[0-9]//' )
     
     
     
    # Si les version de l'application et du client sont différentes
    if [ $VERSION_APPLI != $VERSION_CLIENT ]
    then
    	# La migration automatique a été activée
    	if [ $AUTO_MIGRATION = "true" ]
    	then
    		#On compare d'abord le prefixe en utilisant la comparaison arithmétique
    		if [ $PREFIX_APPLI -ge $PREFIX_CLIENT ]
    		then 
    			if [ $PREFIX_APPLI -eq $PREFIX_CLIENT ]
    			then
    				echo "PREFIX APPLI EGAL"
    				if [ $MINOR_APPLI -ge $MINOR_CLIENT ]
    				then
    					if [ $MINOR_APPLI -eq $MINOR_CLIENT ]
    					then
    						echo "MINOR APPLI EGAL"
    						if [[ $RELEASE_APPLI > $RELEASE_CLIENT ]]
    						then
    						COPY_SCRIPT="1"
    						fi
    					else
    						echo "MINOR APPLI PLUS GRAND"
    						COPY_SCRIPT = "1"
    					fi
               			fi
               		else
               			echo "PREFIX APPLI PLUS GRAND"
               			COPY_SCRIPT="1"
       			fi
    		fi
     
    		if [ $COPY_SCRIPT == "1" ]
    		then 
    			echo "LE TRAITEMENT A EFFECTUER"
    		fi
    Merci à tous et je suis preneur de critiques sur ma solution...

  14. #14
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Tu peux encore réduire ton script en jouant sur le test logique.

    Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #! /usr/bin/ksh
     
    v1="12.2A"
    v2="12.2b"
     
    PREFIX_1=${v1%%+([a-zA-Z])}
    SUFFIX_1=${v1##+([0-9.])}
     
    PREFIX_2=${v2%%+([a-zA-Z])}
    SUFFIX_2=${v2##+([0-9.])}
     
     
    if [[ $PREFIX_1 > $PREFIX_2 ]] || ([[ $PREFIX_1 == $PREFIX_2 ]] && [[ $SUFFIX_1 > $SUFFIX_2 ]])
    then
        echo "$v1 plus grand que $v2"
    fi
    Si tu ne disposes pas du shell Korn (quel dommage!), remplace les splits des préfixes/suffixes par sed. Le test logique reste identique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    PREFIX_1=$(echo $v1 | sed -e 's/[a-z]//' )
    SUFFIX_1=$(echo $v1 | sed -e 's/[0-9]//' )
     
    PREFIX_2=$(echo $v2 | sed -e 's/[a-z]//' )
    SUFFIX_2=$(echo $v2 | sed -e 's/[0-9]//' )

    Pour info, un timing comparé des deux scripts donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Ton script bash
      real    0m0.038s
      user    0m0.040s
      sys     0m0.000s
     
    Bash (ma version)
      real    0m0.030s
      user    0m0.030s
      sys     0m0.000s
     
    Le script Korn
      real    0m0.002s
      user    0m0.000s
      sys     0m0.000s
    Le Korn est souvent plus rapide et en plus, ici, on ne fait plus appel à awk ou sed.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. comparaison nombres flottants
    Par tintin72 dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 24/05/2012, 22h54
  2. Comparaison de nombre dans un tableau.
    Par slackjayo dans le forum Algorithmes et structures de données
    Réponses: 18
    Dernier message: 29/04/2005, 17h21
  3. [MASM] Utiliser un .IF pour une comparaison de nombre signés
    Par Crisanar dans le forum x86 32-bits / 64-bits
    Réponses: 3
    Dernier message: 24/11/2004, 16h32
  4. nombres flottants arrondis aux 5 centimes
    Par nstubi dans le forum Langage
    Réponses: 3
    Dernier message: 17/09/2004, 09h02
  5. [Kylix] Probleme de nombre flottant!!
    Par yopziggy dans le forum EDI
    Réponses: 5
    Dernier message: 02/05/2002, 10h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo