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

JavaScript Discussion :

comparaison nombres flottants


Sujet :

JavaScript

  1. #1
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut comparaison nombres flottants
    Bonjour,

    Je galère dur avec les comparaisons de nombres flottants.
    Dans mon script je récupère des variables de checkboxes qui sont
    des nombres flottants à 2 chiffres après la virgule:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var var1 = parseFloat(document.forms['form'].elements['var1'].value).toFixed(2);     
    var var2 = parseFloat(document.forms['form'].elements['var2'].value).toFixed(2);
    var var3 = parseFloat(document.forms['form'].elements['var3'].value).toFixed(2);
    Puis je les compare entre eux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(parseFloat(var1) + parseFloat(var2) == parseFloat(var3))
    où var1 = 5.20 var2 = 3.40 et var3 = 8.60

    normalement 5.20 + 3.40 = 8.60.
    Alors pourquoi il n'entre pas dans la condition ???

    Y a t-il un problème de cast ?

    Merci d'avance pour votre aide

  2. #2
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 198
    Par défaut
    Bonjour,
    il y a des problèmes avec les nombres en virgule flottant, il te suffit de faire une recherche sur ce forum, cela a été longuement débattu.

    Un question quand même pourquoi parseFloat(er) 2 fois.

    Tu peux travailler sur des nombres entiers (x100)

    Alors pourquoi il n'entre pas dans la condition ???
    il existe peut être, aussi, un problème en amont dans ton code!

  3. #3
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Billets dans le blog
    20
    Par défaut
    A noter que ce n'est pas un problème spécifique à JavaScript mais connu dans beaucoup de langages : The Floating-Point Guide - What Every Programmer Should Know About Floating-Point Arithmetic
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  4. #4
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut
    En effet c'est bien un problème de précision, lors d'une addition toute bête dans ma fonction:
    15.20 + 4.10
    le resultat est: 19.2999999999999999999

    (Note: Je suis sous Firefox/Ubuntu, mais il est probable que ça change avec un autre browser/OS)

    J'ai vu une solution qui consiste à utiliser Math.round en multipliant la
    valeur par 100 puis en divisant le tout par 100 également, (une histoire de puissances je crois) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var result = parseFloat(var1) + parseFloat(var3);
    result = Math.round(result * 100) / 100;
    Source:
    http://en.allexperts.com/q/Javascrip...nipulation.htm

    C'est assez tordu mais ça à l'air de marcher, toutefois j'aimerais savoir si
    c'est une solution fiable.

    Merci pour vos réponses.

  5. #5
    Membre Expert Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Par défaut
    Je pense que tous les navigateurs gèrent la virgule flottante de la même manière sur tous les OS. (il me semble que j'avais fait des tests à l'époque lointaine^^)

    Enfin, je NE pense PAS que cette solution soit fiable, il n'y a aucune raison que la division par 100 ne génère pas d'autres erreurs pour d'autres valeurs.

    La meilleure solution est une conversion en string et plus de recréer tes méthodes de calculs sur les valeurs entières de ce string. Ou alors d'utiliser une librairie de calcul JS.

  6. #6
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut
    Pour mon cas les décimales représentent des prix (donc 2 chiffres après la virgule pas plus), je ne suis pas sûr qu'une librairie de calcul soit vraiment appropriée.

    Y aurait-il un tuto qui expliquerait en détail comment créer des méthodes de calculs sur les valeurs entières ?

  7. #7
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Billets dans le blog
    20
    Par défaut
    Sur des valeurs entières ?
    Le problème vient de la représentation à virgule flottante. S'il n'y a plus de virgule, il n'y a plus de problème
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  8. #8
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut
    ben c'est dans la réponse de Willpower:
    La meilleure solution est une conversion en string et plus de recréer tes méthodes de calculs sur les valeurs entières de ce string.
    Je suppose qu'il fait référence à ça:
    http://floating-point-gui.de/formats/integer/

    Mais c'est très obscure pour moi, c'est pourquoi j'aimerais avoir un peu d'aide.

  9. #9
    Membre Expert Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Par défaut
    Citation Envoyé par tintin72 Voir le message
    ben c'est dans la réponse de Willpower:

    Je suppose qu'il fait référence à ça:
    http://floating-point-gui.de/formats/integer/

    Mais c'est très obscure pour moi, c'est pourquoi j'aimerais avoir un peu d'aide.
    En fait, je faisais référence à faire des calculs entiers mais de savoir replacer la virgule au bon endroit par après, pour des multiplications ou divisions par exemple. Mais si tu n'as besoin que de simples additions, alors ce problème ce ne pose pas :


    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
     
    	Number.prototype.powInt = function(p){
    		return parseInt(this.toFixed(p).replace('.',''));
    	};
    	Number.prototype.unpow = function(p,tmp){
    		return (tmp=this.toString().split('')).splice(tmp.length-p,0,'.'),tmp.join('');
    	};
    	a = 15.20;
    	b = 4.10;
     
    	res = a.powInt(2) + b.powInt(2);
    	res = res.unpow(2);
    	// res = parseFloat(res); // si besoin d'avoir un float plutot qu'un string
     
    	alert(res); // 19.30
    	alert(a+b); // 19.2999999999999999

  10. #10
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut
    Merci beaucoup Willpower pour ce code, 'reste plus pour moi qu'à comprendre ce qu'il fait exactement

    Mais est ce qu'il marche aussi pour les soustractions ?

  11. #11
    Membre Expert Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Par défaut
    Citation Envoyé par tintin72 Voir le message
    Merci beaucoup Willpower pour ce code, 'reste plus pour moi qu'à comprendre ce qu'il fait exactement

    Mais est ce qu'il marche aussi pour les soustractions ?
    Oui pour les soustractions !
    Non pour les multiplications et divisions (enfin, il faut ajuster la virgule au bon endroit).

    Explications :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Number.prototype.powInt = function(p){
    		return parseInt(this.toFixed(p).replace('.',''));
    	};
    Rajoute une méthode powInt aux "Number" qui :

    1) Renvoie un string avec un nombre de décimal fixé à "p".
    2) Supprime le point "." du string.
    3) Converti le string en entier et retourne ce dernier.

    #Donc si ton nombre est 3.4 et p vaut 3 :
    1) Ca converti ton nombre en string "3.400"
    2) Ca supprime le point du string : "3400"
    3) Ca renvoit 3400 (valeur entière)



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Number.prototype.unpow = function(p,tmp){
    		return (tmp=this.toString().split('')).splice(tmp.length-p,0,'.'),tmp.join('');
    	};
    Rajoute une méthode unpow aux "Number" qui :

    1) Converti ton nombre(ou ton string) en string.
    2) Converti ton string en tableau
    3) Insère un point en position "p" en partant de la fin( en écrasant 0 élément).
    4) Reconverti ton tableau en string.

    #Donc si ton nombre est 340 et p vaut 2 :
    1) Ca converti ton nombre en string "340"
    2) Ca converti ton string en tableau ["3","4","0"]
    3) Ca insère dans ton tableau un point à p(2) position de la fin ["3",".","4","0"]
    4) Ca renvoit "3.40"


    Voici enfin l’exécution du brol :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	var a = 15.20, b = 4.1;
    	res =  // 1520+410 = 1930
    		a.powInt(2) // 15.20 -> 1520
    		+ b.powInt(2); // 4.1 -> 410
    	res = res.unpow(2); // place un point à notre 1930 -> 19.30

  12. #12
    Membre éclairé Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Par défaut
    Encore un grand merci pour cette explication claire et détaillée

  13. #13
    Membre Expert Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Par défaut
    Note que mes noms de fonctions (prototypes) ne sont pas top, il y a sans doute beaucoup mieux que unpow et powInt, mais je n'ai pas d'inspiration.

    shiftToInt et unshiftToFloat(String)

    sont peut-être déjà plus explicites ?

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

Discussions similaires

  1. Comparaison de nombres flottants en shell
    Par the_ionic dans le forum Linux
    Réponses: 13
    Dernier message: 30/12/2006, 08h44
  2. [MySQL] Probleme avec les nombres flottants
    Par Seth77 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 04/07/2006, 10h20
  3. comparaison nombre
    Par nicocodi dans le forum C
    Réponses: 6
    Dernier message: 26/08/2005, 12h14
  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