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 :

JS ne sais plus faire une addition


Sujet :

JavaScript

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    313
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 313
    Points : 330
    Points
    330
    Par défaut JS ne sais plus faire une addition
    Bonjour,

    Je suis tombé sur ce qui ressemble bien à un bug de calcul que je ne sais expliquer :

    alert(13000000000000000 + 4); //=> 13000000000000004
    alert(13000000000000000 + 5); //=> 13000000000000004
    alert(13000000000000000 + 6); //=> 13000000000000006


    Firefox 3.0.11 et IE7. Dual-core T2080.
    Firefox 3.0.11, Mac PowerPC G4

    Quelqu'un a une idée ?

    Merci.

  2. #2
    Membre actif Avatar de nod__
    Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2009
    Messages : 176
    Points : 226
    Points
    226
    Par défaut
    C'est normal ça vient de la représentation utilisé par JS des nombres (flottants, ils le sont tous en JS, il n'y a pas «d'integer»).

    Y'a rien ou pas grand chose à faire ^^.

  3. #3
    Expert confirmé
    Avatar de emmanuel.remy
    Inscrit en
    Novembre 2005
    Messages
    2 855
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 855
    Points : 4 045
    Points
    4 045
    Par défaut
    Salut,

    +1 nod__

    Pour compléter, ce n'est d'ailleurs pas qu'un problème lié à JS, mais plus généralement à tous les calculs faits en virgule flottante. En gros un nombre est stocké sous la forme 1.xxxxxxx * 2^n , avec xxxxx la précision. Or cette dernière n'est pas extensible (15 chiffres avec un réel stocké sur 64bits) Moralité, si on ajoute un très petit nombre à un très grand nombre, le résultat peut être uniquement le très grands nombre. Ceux qui ont l'habitude de travailler avec de tels nombres savent gérer ces taux d'erreur, ou calculent autrement.

    Note enfin que de la même manière il est impossible de codifier exactement certains nombres tel que 0.1; de là: 0.1 * 0.196 = 0.019600000000000003, ce qui laisse augurer des affichages étranges lors des calculs de TVA par exemple...

    ERE

  4. #4
    Rédacteur
    Avatar de marcha
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2003
    Messages
    1 571
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 571
    Points : 2 351
    Points
    2 351
    Par défaut
    Salut,

    Pour palier à ce problème, il faut imposer à JS de travailler en virgule fixe,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    alert((13000000000000000).toFixed(0) + 4);
    alert((13000000000000000).toFixed(0) + 5);
    alert((13000000000000000).toFixed(0) + 6);

  5. #5
    Membre actif Avatar de nod__
    Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2009
    Messages : 176
    Points : 226
    Points
    226
    Par défaut
    Ça c'est fun. Je pensais que toFixed renvoyais tout le temps une chaine, ben je me suis gourré.

    Par contre faut faire gaffe, en passant 1 ou plus en argument on récupère une chaine et là… ça calcule comme je parle allemand…

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    313
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 313
    Points : 330
    Points
    330
    Par défaut
    C'est normal, c'est normal... Si vous me le dites.

    Pourtant :
    (13000000000000000 + 5) < Number.MAX_VALUE => true
    Number.MAX_VALUE = 1.7976931348623157e+308
    Le mieux qu'il peut afficher en entier : alert(1.7976931348623157e+20)
    Au delà, JS passe par la notation 'e+'.

    Mais ok pour la représentation, mais ça ne va pas être simple :
    alert(1.0e+15 + 5) //=> 1000000000000005 ok !
    alert(13 * 1.0e+15) //=> 1300000000000000 ok !

    alert(13 * 1.0e+15 + 5) //=> 1300000000000004 KO
    alert(1.3e+16 + 5) //=> 1300000000000004 KO
    alert((1.3e+16) + 5.0) //=> 1300000000000004 KO
    alert((1.3e+16) + 0.5e+1) //=> 1300000000000004 KO

    alert(new Number( 1.3e+16) + new Number(0.5e+1)) //=> KO
    alert(new Number( 1.3e+16 + 0.5e+1)) //=> KO

    A ce stade, je me dis que si Number permet de représenter de très grands nombres, il ne permet pas de les additionner.

    Et même avec ça :
    alert((1.3 + (0.5/1.0e+15)) * 1.0e+16) //=> KO !

    C'est pas beaucoup mieux. Le résultat est finalement très hasardeux.

    J'essaie une ruse :
    alert(((13.0 * 1.0e+15)/1.0e+8) + (0.5e+1/1.0e+8)) //=>130000000.00000004
    Pas mieux...

    J'ai l'impression que je vais devoir me créer une classe BigInteger...

    Moi qui croyait qu'on était passé à l'air du 64 bits et vu que des procs 128 bits arrivent. C'est encore les FPUs qui trainent.

    Merci à vous.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    313
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 313
    Points : 330
    Points
    330
    Par défaut
    Citation Envoyé par marcha Voir le message
    Salut,

    Pour palier à ce problème, il faut imposer à JS de travailler en virgule fixe,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    alert((13000000000000000).toFixed(0) + 4);
    alert((13000000000000000).toFixed(0) + 5);
    alert((13000000000000000).toFixed(0) + 6);
    Ah...................

    Merci.

  8. #8
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 640
    Points : 66 669
    Points
    66 669
    Billets dans le blog
    1
    Par défaut
    j'avais oublié le toFixed ^^

    j'en étais rendu à trouver une affreuse bidouille :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var chiffre=13000000000000000
    var cl=chiffre.toString().length
    alert(chiffre.toPrecision(cl) + 4);
    alert(chiffre.toPrecision(cl) + 5);
    alert(chiffre.toPrecision(cl) + 6);
    qui en fait revient au même puisqu'elle sort des virgules flottantes ...

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    313
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 313
    Points : 330
    Points
    330
    Par défaut
    Arf... C'était trop beau pour être vrai.

    L'utilisation de Math (en l'occurrence Math.max()) me bouffe l'unité.

    Pour cause :
    alert((13000000000000000).toFixed(0) + 5);

    Aurait pu être bien, mais il s'agit d'une concaténation, pas d'une addition.

  10. #10
    Rédacteur
    Avatar de marcha
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2003
    Messages
    1 571
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 571
    Points : 2 351
    Points
    2 351
    Par défaut
    Arg, mea culpa, j'en ai fait une bien grosse là :-)

  11. #11
    Expert confirmé
    Avatar de emmanuel.remy
    Inscrit en
    Novembre 2005
    Messages
    2 855
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 855
    Points : 4 045
    Points
    4 045
    Par défaut
    Citation Envoyé par kernelfailure Voir le message


    J'ai l'impression que je vais devoir me créer une classe BigInteger...

    Merci à vous.
    D'autres s'y sont attelés : http://silentmatt.com/biginteger/ , http://www.onicos.com/staff/iz/amuse...ert/BigInt.txt

    ERE

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    313
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 313
    Points : 330
    Points
    330
    Par défaut
    Citation Envoyé par emmanuel.remy Voir le message
    Oui, j'ai vu ça (le premier liens). C'est pas mal complexe tout ça.

    N'ayant pas trouvé une qui me plaise, je viens de terminer une petite classe qui suffit à mon besoin (add(), mul(), min(), max()).
    Entier strictement positif pour le moment.

    Merci

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

Discussions similaires

  1. XI - Extraire une somme dans une periode pour faire une addition
    Par campia dans le forum SAP Crystal Reports
    Réponses: 5
    Dernier message: 06/12/2007, 16h41
  2. Je ne sais pas faire une addition ?
    Par sam80 dans le forum Delphi
    Réponses: 8
    Dernier message: 18/04/2007, 15h13
  3. Faire une addition, mais à l'horizontal
    Par deejay2221 dans le forum Access
    Réponses: 4
    Dernier message: 10/06/2006, 08h56
  4. Requête pour faire une addition sur autres requêtes
    Par guenfood dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 06/06/2006, 18h35
  5. Faire une addition en asp
    Par PrinceMaster77 dans le forum ASP
    Réponses: 9
    Dernier message: 29/11/2004, 15h25

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