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

Lazarus Pascal Discussion :

Etrange réaction de la fonction StrToFloat [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Membre éclairé
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2008
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juillet 2008
    Messages : 389
    Par défaut Etrange réaction de la fonction StrToFloat
    Bonsoir,
    je reviens sur mon problème étrange concernant la "réaction" de la fonction StrToFloat sous lazarus 1.2.4 en 64 bit sous fedora 20.
    J'utilise des tables sqlite3 où les champs de données sont des chaînes de caractères même pour les valeurs dates ou numériques avec décimales ou pas. J'utilise les composants natifs de lazarus.
    J'utilise la fonction StrToFloat pour convertir les valeurs lues dans mes tables quand je sais que la chaîne enregistrée comporte des décimales et je mets le résultat dans une variable déclarée comme Double pour pouvoir utiliser le résultat afin d'effectuer des calculs. Ensuite j'effectue l'opération inverse FloatToStr sur ce nouveau résultat qu je mets en forme pour avoir dans mon enregistrement une chaîne de x caractères avec le nombre de décimales voulues.
    Exemple : Champ TOTAL est prévu pour 6 caractères une virgule et 2 caractères pour la valeur décimale si ma valeur calculée me donne 123.4 avec un point la conversion me donne 123,4 avec une virgule j'ajoute 3 espaces en début de chaîne puis un zéro en fin de chaîne.
    Maintenant voila mon problème dans une de mes applications utilisant cette façon de faire je suis obligé d'ajouter une fonction Trim comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ML_PREMIER:=data.Vehicule.FieldByName('L_PREMIER').AsString;
      XL_PREMIER:=StrToFloat(Trim(ML_PREMIER));
    sinon j'ai un message d'erreur de conversion.
    J'ai fait de nombreux essais avec une application de test en il effectuant les mêmes opérations avec la même base et je n'ai pas ce problème.
    J'ai dans l'application concernée ajouter une unité pour effectuer le me essai et là j'ai a nouveau l'erreur de conversion.
    J'ai refait un autre essai en recréant le projet et en y ajoutant les unités d'origine même problème.
    J'ai tenté la fonction de l'EDI nettoyer les fichiers de compilation pas de changement j'ai pensé peut-être à tords que le problème venait du fichier des ressources *.lrs, j'ai renommé ce fichier pour obliger sa recréation qui n'a pas eu lieu et le résulta est le même avec juste une particularité un nouveau fichier *.lfm se trouve dans le dossier lib/x86_64-linux.
    Ce problème semble lié à cette application car j'utilise la même utilisation dans d'autres sans problème.
    Alors où chercher pour corriger cette anomalie ou devrais-je la réécrire entièrement.
    L'un d'entre vous aurait-il une idée dans mes recherches.
    Merci d'avance

  2. #2
    Membre émérite
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Par défaut
    Bonjour,

    Est-ce qu'il n'y a pas des blancs dans le champ de type chaine de la table ?
    Il faudrait l'afficher entre quotes pour en être sûr, avec quelque chose du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ShowMessage ( QuotedStr(StringReplace(date.FieldByName('xxx').AsString,' ', '*', [rfReplaceAll]) ));
    Si c'est bien le cas, il faut trouver pourquoi quand ce champ est rempli. C'est là que se situe le problème et pas au décodage.

    Mais pourquoi diable utiliser des champs de type chaîne pour stocker du numérique ?
    C'est plus simple, plus sûr et plus efficace avec des champs numériques.

    A+

  3. #3
    Membre éclairé
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2008
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juillet 2008
    Messages : 389
    Par défaut
    Bonjour Tintinux,
    Oui il y a des espaces codés 20 en hexa mais pourquoi avec les mêmes fonctions et la même base (fichier de la base copié dans le répertoire de test) je n'ai pas le problème avec l'application de test.
    Précision cette écriture fonctionnait bien il y a plusieurs mois.
    Autre particularité mais anciennes unités ont dans mon dossier d'écriture de mon projet 3 fichiers *.pas *.lfm et *.lsr et dans le sous dossier lib/x86_64-linux 2 fichiers *.o et *.ppu et une nouvelle créée pour mes test à dans le principal 2 fichiers *.pas et *.lfm et dans le même sous dossier 3 fichiers *.o *.ppu et *.lfm donc 2 fichiers décrivant la fiche sauf erreur de ma part mais plus de fichier *.lrs fichier de ressources sauf encore erreur de ma part.
    Enfin pourquoi j'utilise des champs chaînes dans mes bases sqlite c'est une habitude ancienne venant dbase et son langage de programmation afin de faciliter l'affichage des données et leur mise en forme pour impression, habitude qui a suivi sous delphi 4 (c'est vieux) et j'ai trouvé en passant avec sqlite sous lazarus que la création de base était plus simple sous cette forme et à part ce problème qui ne me semble pas lié à cette façon de faire je ne pense pas modifier mes applications actuelles.
    Il y a aussi un point important toute la documentation que j'ai trouvée sur sqlite est en anglais langue que je ne pratique pas.
    A+

  4. #4
    Membre émérite
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Par défaut
    Es-tu bien certain que ton programme de test est capable d'exécuter StrToFloat quand il y a des espaces à la fin de la chaîne à décoder ?
    En tous cas mon Lazarus 1.2.4 ne le peut pas.

    Je parierais soit qu'il n'y en a pas pour le cas que tu testes, soit éventuellement qu'il existe une option dans SqlLite ou dans les composants d'accès aux données, qui élimine ces espaces en lisant les données, et que cette option est inactive dans le programme fautif, et active dans le programme de test. Je n'utilise pas les composants d'accès aux données de Lazarus (seulement ZeosLib), et jamais SqlLite, alors je ne sais pas.

    Ajoute dans les 2 programmes cette vérification, et active les assertions dans les options du projet si ce n'est pas déjà le cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Assert( Chaine = '' or Chaine[length(Chaine) = ' ', 'il y a des espaces !! ');
    En tous cas je ne suis pas au courant d'un changement sur ce point dans Lazarus.
    Il ne devrait pas être utile d'avoir de fichier .lrs avec les .pas et dfm, sauf si ton source le réclame avec un $R, mais je ne pense pas que cela ait un rapport avec le sujet.

    Au fait, ça fait plus de 20 ans que j'ai abandonné dBase, mais je me rappelle bien qu'il existait déjà des champs numériques...

    A+

  5. #5
    Membre éclairé
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2008
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juillet 2008
    Messages : 389
    Par défaut
    Bonsoir Tintinux,
    Dans la mise en forme des données d'origine numérique transformées en chaînes il n'y a pas d'espace en fin de chaîne ils sont ajoutés au début de la chaîne pour avoir une longueur déterminée.
    exemple si j'ai une valeur numérique calculée égale à 12,3 et que j'ai prévue son écriture dans un champ de 10 caractères avec 2 décimales dans ma table j'ajoute un zéro en fin de chaîne et 5 espaces en début de chaîne ce qui me donne *****12,30 ceci me permet d'avoir une chaîne formatée en particulier pour mes affichages dans des edit ou dbedit etc...
    concernant la commande assert..... je ne la connais pas et pour les options de mes projets je suis dans le standard fourni à l'installation je ne suis pas un spécialiste

    concernant la directive de compilation c'est aussi celles d'origines

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    implementation
     
    {$R *.lfm}
    avec une différence certaines unités ont une commande INITILIZATION en fin
    A+

  6. #6
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 120
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 120
    Par défaut
    Salut,
    Citation Envoyé par ovni76 Voir le message
    (...) ceci me permet d'avoir une chaîne formatée en particulier pour mes affichages dans des edit ou dbedit etc.
    Tu t'es compliqué la vie pour rien, tu aurais pu rester en données numériques dans la base et pour leur affichage, jette un œil à l'aide de la fonction FloatTostrF qui fait ce que tu fais...

  7. #7
    Membre Expert

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Par défaut
    Bonjour.

    Testé sous Lazarus 1.2.4 32 bit sous win7 64bit : les espaces avant ou après ne provoquent pas d'erreur.
    Testé sous Lazarus 1.2.2 32 bit sous linus mint 32bit : erreur de conversion !

    Pourquoi ajouter des espaces pour aligner ?
    TLabel, TEdit (et je suppose aussi TDBEdit) ont la propriété Alignment. La plupart du temps, pour des nombres, on utilise taRightJustify.

    Cordialement
    Thierry

  8. #8
    Membre émérite
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Par défaut
    Bonjour,

    N'oubliez pas que les fonctions de décodage comme StrToFloat dépendent des paramètres de "régionalisation".

    Exemple :

    Le code suivant retourne une erreur tout à fait logique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    DefaultFormatSettings.ThousandSeparator := ' ';  // un espace
    DefaultFormatSettings.DecimalSeparator := '.';
    ShowMessage(floatToStr(StrToFloat('  5.2'))); // il y a plusieurs espaces, donc plusieurs séparateurs de milliers au début de la chaîne
    Alors que celui-ci fonctionne bien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    DefaultFormatSettings.ThousandSeparator := '*';   // autre chose
    DefaultFormatSettings.DecimalSeparator := '.';
    ShowMessage(floatToStr(StrToFloat('  5.2')));  // les espaces au début sont acceptés
    Au lieu d'assigner un caractère à ThousandSeparator vous obtiendrez le même résultat en changeant les paramètres régionaux de Windows ou de Linux avant l'exécution.

    Je pense que cela peut expliquer vos soucis.

    NB : d'une manière générale, il est préférable d'écrire des applications qui acceptent tous les paramètres régionaux, mais aussi d'éviter de les assigner "en dur" comme dans l'exemple, ou alors très temporairement si vous avez besoin d'enregistrer une valeur numérique sous forme de chaîne (dans un try/finally).

  9. #9
    Membre éclairé
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2008
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juillet 2008
    Messages : 389
    Par défaut
    Bonjour Tintinux,
    Ayant eu le souci de l'environnement par le passé dans ma fiche principale je mets cette procédure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TFauto.FormCreate(Sender: TObject);
    begin
      // préparation de l'environnement
      defaultFormatSettings.ShortDateFormat:='DD/MM/YYYY';
      defaultFormatSettings.DateSeparator:='/';
      defaultFormatSettings.DecimalSeparator:=',';
    end;
    Concernant l'anomalie avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ML_PREMIER:=data.Vehicule.FieldByName('L_PREMIER').AsString;
      XL_PREMIER:=StrToFloat(Trim(ML_PREMIER));
    Je vois que je ne suis pas le seul à avoir cette erreur sous linux
    En regardant d'autres messages plus récents de Pierre il y a des différences de plus en plus fréquentes entre la version windows ou linux de lazarus c'est bien dommage.
    J'ai reçu pas mal de conseils que je mettrais en application lors de la création d'une nouvelle application comme l'utilisation des champs numériques avec sqlite.
    En attendant j'ajouterais le Trim.
    Donc je vous remercie tous pour votre aide et je vais validé résolu.
    A+
    PS : un complément une conversion similaire mais avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    XCOMPTEUR:=StrToInt(MaskCompteur.Text);
    qui fonctionnait aussi par le passé donne maintenant une erreur si il y a un espace en fin de maskedit. Etrange

  10. #10
    Membre émérite
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    469
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 469
    Par défaut
    Bonjour

    Tu n'as apparemment pas bien lu mon message.

    C'est la valeur donnée par le système à ThousandSeparator qui est la cause de ton "problème", et Lazarus ne fait que la prendre en compte.

    Et, je le répète, c'est une erreur de forcer les formats de date et numérique dans un programme. Cela signifie qu'il ne seront pas les mêmes dans tes applications que dans d'autres présentes sur le même système.

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

Discussions similaires

  1. [Lazarus] Problème étrange avec l'utilisation de la fonction StrToFloat
    Par ovni76 dans le forum Lazarus
    Réponses: 7
    Dernier message: 07/09/2014, 18h01
  2. comportement etrange de la fonction detrend
    Par Dombrai dans le forum MATLAB
    Réponses: 2
    Dernier message: 12/12/2013, 16h09
  3. Réponses: 2
    Dernier message: 10/01/2008, 13h45
  4. fonction printf
    Par ydeleage dans le forum C
    Réponses: 7
    Dernier message: 30/05/2002, 11h24
  5. FOnction api specifiant la position de la souris
    Par florent dans le forum C++Builder
    Réponses: 4
    Dernier message: 15/05/2002, 20h07

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