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

Langage Delphi Discussion :

[Android] Comment assurer la précision d'un nombre réel saisi par l'utilisateur ?


Sujet :

Langage Delphi

  1. #1
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    1 976
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 1 976
    Points : 6 221
    Points
    6 221
    Par défaut [Android] Comment assurer la précision d'un nombre réel saisi par l'utilisateur ?
    Bonjour à tous,

    J'ai une app Android qui demande à l'utilisateur de saisir un nombre réel mais au final j'obtiens un nombre réel avec des décimales erronées. Pour une saisie "0.3", je me retrouve avec une valeur *0.30000001"!!!

    Je bricole le bout de code suivant pour visualiser ce qui se passe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    var
     mysingle: single;
    ...
    mysingle:=StrToFloat(StringReplace(String(DataInput.Text),'.',FormatSettings.DecimalSeparator,[])); 
     
    FinalValue.Text:=FloatToStrF(mysingle, ffGeneral, 8, 3,G_myDecimalSeparator);
    Je saisie dans DataInput.text le string "0.3* et j'obtiens dans FinalValue.Text le string *0.30000001"!!!

    Questions:

    1. Comment éviter ce problème de précision?

    2. Avec la mention "FloatToStrF(...8,3...", je devrais bien avoir 3 digits après la virgule, non?

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 763
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 763
    Points : 13 381
    Points
    13 381
    Par défaut
    D'après l'aide, la précision doit être inférieure ou égale à 7 pour un single.

  3. #3
    Membre actif
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2014
    Messages
    107
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant fonctionnel

    Informations forums :
    Inscription : Décembre 2014
    Messages : 107
    Points : 237
    Points
    237
    Par défaut
    Bonjour,

    La précision d'un nombre réel est assurée par la fonction RoundTo dans l'unité Math.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    uses Math;
    ..
    ..
    FinalValue := RoundTo(1230.765 ), -2);   // = 1230.76 
    FinalValue := RoundTo(1230.765 ), -4);   // =  1230.7650 
    FinalValue := RoundTo(1230.765 ), 0);    // = 1230
    FinalValue := RoundTo(1230.765 ), 2);    // = 1200
    solilog

  4. #4
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 504
    Points : 2 776
    Points
    2 776
    Billets dans le blog
    10
    Par défaut
    Désolé tu ne peux rien faire.
    L'exemple ci-dessous n'est pas particulier à Delphi. Le processeur effectue les calculs en base 2. On sait donc exprimer un demi, un quart, un huitième, etc. soit 1 / 2^n mais on ne sait pas décrire 1/10 ou 1/100 qui sont des nombres incommensurables en base 2. Voilà donc un résultat surprenant.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    …
    var
      i1, i2: Extended ;
    begin
      readln (i2) ;
      i1 := i2 + i2 + i2 + i2 + i2 - 0.05 ;
      writeln (FloatToStr(i1));
      readln ;
    end.
    Entrer la valeur 0.01
    Donc 0.01+0.01+0.01+0.01+0.01-0.05=0
    En fait le résultat donne
    -3.3881317890172E-21
    Pareil pour excel et autres

  5. #5
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    1 976
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 1 976
    Points : 6 221
    Points
    6 221
    Par défaut
    Merci à tous pour vos réponses

    J'ai fini par réussir à avoir un "0.3" quand l'utilisateur tape "0.3" (expliquer comme cela, j'ai l'impression d'avoir réaliser un exploit digne de junior qui fait son premier rôt!)

    Il faut...

    1. Remplacer le type single par un type currency

    2. Appliquer la fonction RoundTo

  6. #6
    Membre averti
    Homme Profil pro
    Ingénieur développement en retraite
    Inscrit en
    Juin 2002
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement en retraite
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2002
    Messages : 410
    Points : 307
    Points
    307
    Par défaut
    Bonsoir,

    J'ai rentré la formule d'Alweber dans une case de LibreOffice Calc : =0,01+0,01+0,01+0,01+0,01-0,05 et même en format scientifique j'ai bien 0 comme résultat ou plus exactement 0,00E+00.

  7. #7
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 374
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 374
    Points : 3 152
    Points
    3 152
    Par défaut
    Bonjour,

    idem pour moi : dans mon Excel2000 : =0,01+0,01+0,01+0,01+0,01-0,05 = 0,00000000000E+00 ?
    je ne sais pas comment Excel se débrouille. Il faudrait tester avec un Excel récent !!!

    A+
    Charly

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Excel utilise un Double : L’arithmétique à virgule flottante peut entraîner des résultats imprécis dans Excel
    Et il y a justement un article sur Nombres binaires périodiques et calculs ayant des résultats proches de zéro
    Vous pensez bien qu'un outil de bureautique a été extrêmement travaillé pour gérer ce genre de problème connu depuis l'avènement des calculs en nombre flottant
    Et à l'affichage, on peut penser qu'Excel considère certaines valeurs avec une précision proche de la marge d'erreur comme devant être affiché plus simplement, un double ayant une précision de 15 digits

    Ce n'est pas un problème Android mais un problème lié au IEEE 754 :
    Problème d'arrondi en Delphi
    Utilisation de l'arrondi sur un calcul
    roundto simperoundto currency arrondi incorrect
    Round : arrondir à l'entier supérieur quand on est à 0,5 ?

    mais comme répété plusieurs fois, l'astuce est d'arrondir deux fois, typiquement, les calculs sont effectués sur 4 digits de plus que nécessaire, le premier arrondi sur 2 digits supplémentaires et enfin l'arrondi à 0 digits
    Ensuite TOUJOURS utiliser un Compare avec Epsilon pour définir la précision souhaité dans les calculs, ne jamais utiliser une valeur flottante brute, elle requiert un soin particulier pour la rendre pertinenete

    Par exemple, le calcul du taux change de l'Euro lors de son instauration en France
    6,55957 * 1.01, soit 7 digits potentiels lors de la conversion des centimes, il faut choisir un au moins 11 digits après la virgule, un Double fera l'affaire

    6,6251657, on arrondi à 6,625167 puis à 6,6252, ça c'est le Currency un format monétaire transitoire
    comme l'usage veut que l'on n'affiche que les centimes 6,62 sera affiché mais l'on conserve 0,0052 sur un compte d'arrondi, si l'on stocke aussi la valeur arrondie

    Le Currency n'est pas un format flottant, c'est un calcul entier avec une simulation d'une virgule à 4 digit
    Il est typiquement conçu pour la calcul de montant avec potentiellement des nombres de type 1.01 x 1.01, la gestion des centimes sur 4 digits pour assurer un arrondi sur 2, et même dans ce cas, ce n'est pas l'arrondi mathématique qu'il faut utiliser mais l'arrondi bancaire.
    Cela fait débat : Arrondi classique vs Arrondi bancaire
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 504
    Points : 2 776
    Points
    2 776
    Billets dans le blog
    10
    Par défaut
    Citation Envoyé par Charly910 Voir le message
    Bonjour,
    idem pour moi : dans mon Excel2000 : =0,01+0,01+0,01+0,01+0,01-0,05 = 0,00000000000E+00 ?
    je ne sais pas comment Excel se débrouille. Il faudrait tester avec un Excel récent !!!
    A+
    Charly
    Voici le fichier pour tester
    Les deux autres valeur du fichier sont égales à 1/2^n donc le résultat est OK
    Fichiers attachés Fichiers attachés

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    Il faut différencier l'affichage de la valeur brute comme l'a mis en évidence ALWEBER
    Excel calcule avec un Double avec les problèmes connus mais est assez malin pour afficher une valeur corrigée, pour la plupart des utilisateurs c'est convenable
    mais pour les calculs, il ne peut pas se permettre d'arrondir
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. Réponses: 8
    Dernier message: 14/10/2011, 16h26
  2. comment concatiner des strings avec des nombre
    Par Sara83 dans le forum MATLAB
    Réponses: 3
    Dernier message: 18/10/2006, 13h06
  3. Comment calculer des moyennes sur des nombres positifs
    Par robertetgorgette dans le forum Access
    Réponses: 2
    Dernier message: 20/07/2006, 14h05
  4. [VB.NET] Comment récupérer le séparateur d'un nombre
    Par Lois dans le forum Windows Forms
    Réponses: 4
    Dernier message: 29/10/2004, 12h47

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