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 Pascal Discussion :

Problème avec la fonction Trunc


Sujet :

Langage Pascal

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 21
    Points : 16
    Points
    16
    Par défaut Problème avec la fonction Trunc
    Pour des valeurs entieres multiples de 13, TRUNC me renvoie la valeur inférieure.

    Ex:

    TRUNC(0.65/0.05) = 12

    TRUNC(5.2/0.1) = 51

    TRUNC(1.3/0.1) = 12

    alors que

    TRUNC(13) = 13...

    superstition???? ou magie

  2. #2
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 845
    Points
    4 845
    Par défaut
    C'est certainement un problème dû à la division (multiplication) réelle. Tu travaille avec des réels donc le calcul n'est qu'une succession d'arrondis. Le résultat obtenu pour 5.2 / 0.1 est peut-être 5.1999...e1. Donc quand tu tronques, tu retombes sur 51.

    Pour bien faire, il faudrait peut-être faire un test sur la valeur obtenue, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    const limite = 0.001;
    ...
    res := 5.2 / 0.1;
    tronc := TRUNC(res);
    if TRUNC(res + limite) > tronc then
       tronc := tronc+1;
    Donc tu introduis un nombre "limite" que tu considères comme négligeable dans tes calculs et si ton résultat + cette limite dépasse la dizaine alors c'est qu'il y'a eu une erreur d'arrondi. Normalement il devrait être de l'ordre de la précision de la mantisse, ce qui dépend de la plateforme, mais 1e-15 devrait être convenable.

  3. #3
    Membre éclairé
    Avatar de denokan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2002
    Messages : 434
    Points : 746
    Points
    746
    Par défaut
    sur mon Turbo Pascal 7.01 téléchargé sur DVP, WriteLn(Trunc(5.2 / 0.1)) m'affiche bien 52 à l'écran .... sur quel compilateur travailles-tu ?
    Donnez un poisson à un homme et il mangera pendant un jour... Apprenez-lui à pêcher et il s'assiéra dans une barque et boira de la bière toute la journée

  4. #4
    Responsable Pascal, Lazarus et Assembleur


    Avatar de Alcatîz
    Homme Profil pro
    Ressources humaines
    Inscrit en
    Mars 2003
    Messages
    7 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ressources humaines
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2003
    Messages : 7 939
    Points : 59 409
    Points
    59 409
    Billets dans le blog
    2
    Par défaut
    Bonjour !

    Par contre, Free Pascal 2.0.2 et Virtual Pascal 2.1 renvoient tous deux 51.
    Règles du forum
    Cours et tutoriels Pascal, Delphi, Lazarus et Assembleur
    Avant de poser une question, consultez les FAQ Pascal, Delphi, Lazarus et Assembleur
    Mes tutoriels et sources Pascal

    Le problème en ce bas monde est que les imbéciles sont sûrs d'eux et fiers comme des coqs de basse cour, alors que les gens intelligents sont emplis de doute. [Bertrand Russell]
    La tolérance atteindra un tel niveau que les personnes intelligentes seront interdites de toute réflexion afin de ne pas offenser les imbéciles. [Fiodor Mikhaïlovitch Dostoïevski]

  5. #5
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    192
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 192
    Points : 176
    Points
    176
    Par défaut
    idem Free pascal 1.0.6 ça donne du 12 au lieu de 13 !

    je pense que c'est vraiment un bug et même que c'est grave comme problème !

    j'ai essayé avec Freepascal de mettre l option compatible avec TP 7.0 mais ça ne change rien : le resultat reste faux !

    sinon ce n'est pas trop une fonction que j'utilise (je prefère quand cela est possible) utiliser INT mais quand même ça fait désordre !
    Un bon exemple vaut mieux qu'une longue explication confuse...

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 21
    Points : 16
    Points
    16
    Par défaut
    Merci de vos réponses,


    C'est certainement un problème dû à la division (multiplication) réelle. Tu travaille avec des réels donc le calcul n'est qu'une succession d'arrondis. Le résultat obtenu pour 5.2 / 0.1 est peut-être 5.1999...e1. Donc quand tu tronques, tu retombes sur 51.
    Le plus étonnant est que cela intervient seulement pour les multiples de 13. Donc le type REAL n y est pour rien ...

    Quant à moi, j utilises le compilateur de VAX VMS.

  7. #7
    Blue_Strike
    Invité(e)
    Par défaut
    salut,
    ce qui est sûr est que les ordinateurs font le calcul avec une telle certitude variant en fonction de l'espace mémoire utilisé pour sauvegarder une valeure (le nbre des bits representant la valeur ) d'où une division comme celle ci 5.2/0.1 donne 51.9999999999... qui est pratiquement = 52. Dans ce niveau, le compilateur fait intervenir en appelant la fonction Trunc, y en a des compilaeteurs qui te donne 52 et d'autre qui donne 51 comme résultat.
    Pour la remarque du l'entier 13 et ses multiple, bah je c pas exactement le truc, mais j'aimerai bien le savoir...
    ++

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Bonjour,
    Citation Envoyé par Blue_Strike
    salut,
    ce qui est sûr est que les ordinateurs font le calcul avec une telle certitude variant en fonction de l'espace mémoire utilisé pour sauvegarder une valeure (le nbre des bits representant la valeur ) d'où une division comme celle ci 5.2/0.1 donne 51.9999999999... qui est pratiquement = 52. Dans ce niveau, le compilateur fait intervenir en appelant la fonction Trunc, y en a des compilaeteurs qui te donne 52 et d'autre qui donne 51 comme résultat.
    Pour la remarque du l'entier 13 et ses multiple, bah je c pas exactement le truc, mais j'aimerai bien le savoir...
    ++
    Alors ceux qui donnent 52 font une erreur : TRUNC, c'est la partie entière d'un nombre, donc = 51 pour 51.9999999999

    Et les calculs sur des réels sont toujours approximatifs, le problème étant effectivement dû à la représentation de la valeur (qui change, en particulier avec les REAL des compilateurs.
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  9. #9
    Responsable Pascal, Lazarus et Assembleur


    Avatar de Alcatîz
    Homme Profil pro
    Ressources humaines
    Inscrit en
    Mars 2003
    Messages
    7 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ressources humaines
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2003
    Messages : 7 939
    Points : 59 409
    Points
    59 409
    Billets dans le blog
    2
    Par défaut
    Il n'y a pas que la valeur 13 qui soit concernée !

    N'oublions pas qu'il y a une différence fondamentale entre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Begin
      WriteLn(Trunc(4.0/0.4));
    End.
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Var a, b : Real;   // Ou tout autre type de réel
    Begin
      a := 4.0;
      b := 0.4;
      WriteLn(Trunc(a/b));
    End.
    Dans le premier cas, c'est le compilateur qui effectue le calcul (troncature comprise) et qui code le résultat en dur dans l'exécutable; dans le second cas, la fonction Trunc de la RTL est réellement appelée lors de l'exécution. Vérifié dans les outputs Assembleur générés lors de la compilation.

    J'ai fait une petite expérience avec Virtual Pascal 2.1 :
    - Dans le 1er cas : résultat = 10
    - Dans le 2ème cas avec le type Real : résultat = 9
    - Dans le 2ème cas avec le type Double : résultat = 9
    - Dans le 2ème cas avec le type Extended : résultat = 10.
    Règles du forum
    Cours et tutoriels Pascal, Delphi, Lazarus et Assembleur
    Avant de poser une question, consultez les FAQ Pascal, Delphi, Lazarus et Assembleur
    Mes tutoriels et sources Pascal

    Le problème en ce bas monde est que les imbéciles sont sûrs d'eux et fiers comme des coqs de basse cour, alors que les gens intelligents sont emplis de doute. [Bertrand Russell]
    La tolérance atteindra un tel niveau que les personnes intelligentes seront interdites de toute réflexion afin de ne pas offenser les imbéciles. [Fiodor Mikhaïlovitch Dostoïevski]

  10. #10
    Expert confirmé
    Avatar de Loceka
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    2 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 2 276
    Points : 4 845
    Points
    4 845
    Par défaut
    Donc c'est bien une erreur d'approximation dûe à la taille de la mantisse ?

    La solution que je proposait est donc valide il me semble, même si c'est plus ou moins du bidouillage...

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Bonjour,

    Oui, c'es du bidouillage, mais on n'y échappe pas, quel que soit le langage utilisé.

    Une alternative serait d'utiliser des réels de précision quelconque, mais de toute manière ce ne serait que décaler le problème, vu que, bien entendu, on ne peut utiliser une précision infinie, qui serait nécessaire pour représenter exactement n'importe quelle valeur.

    Et le prix serait le temps de calcul, puisque cela interdirait d'utiliser l'unité de calculs flottants du processeur. De quoi avoir besoin d'une cafetière en attendant la fin d'un calcul.
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  12. #12
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    192
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 192
    Points : 176
    Points
    176
    Par défaut
    Oui, c'es du bidouillage, mais on n'y échappe pas, quel que soit le langage utilisé.
    personnellemnent ça me gêne quand même..
    en fonction du compilateur on a 12 ou 13
    en fonction de déclaré en variable ou directement en calcul dans le write
    je pense que le systeme d exploitation doit aussi jouer si on est sur 16 32 ou 64 bits ?

    donc je m'imagine je fais un programme et si j'ai 13 ma barriière se baisse quand le train passe sinon je la laisse ouverte.

    je change de compilateur ou si je recompile pour une raison ou pour une autre et ma barriere ne se baisse plus... parce que j'ai 12.

    programmer n'est pas bidouiller tout de même... ??

    sur un code de 100 lignes on peut s'en apercevoir mais si mon programme fait 20000 lignes ... et si en interne j'ai de temps en temps 12.000000001 ou 11.999999999 difficile quand même à deceler...
    Un bon exemple vaut mieux qu'une longue explication confuse...

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Bonjour,
    Citation Envoyé par JoseF
    personnellemnent ça me gêne quand même..
    en fonction du compilateur on a 12 ou 13
    en fonction de déclaré en variable ou directement en calcul dans le write
    je pense que le systeme d exploitation doit aussi jouer si on est sur 16 32 ou 64 bits ?

    donc je m'imagine je fais un programme et si j'ai 13 ma barriière se baisse quand le train passe sinon je la laisse ouverte.

    je change de compilateur ou si je recompile pour une raison ou pour une autre et ma barriere ne se baisse plus... parce que j'ai 12.

    programmer n'est pas bidouiller tout de même... ??

    sur un code de 100 lignes on peut s'en apercevoir mais si mon programme fait 20000 lignes ... et si en interne j'ai de temps en temps 12.000000001 ou 11.999999999 difficile quand même à deceler...
    Quand on travaille avec les réels, il faut fraire très attention, et le résultat des calculs dépend de la représentation en mémoire, soit en natif du processeur, soit autre.

    Et ce que tu obtiens avec write est une approximation de plus par rapport à la valeur effectivement stockée (arrondi dû aux nombres de chiffres que tu demandes en affichage).

    Le seul moyen de "contourner" ce problème, est d'accepter le test pour vrai si si les valeurs testées sont suffisamment proches ("suffisamment proche" reste à définir pour chacun, sachant que ça va dépendre de l'ordre de grandeur de la valeur, dû à la précision limitée des réels).

    Si tout ça te pose problème, n'utilise que des entiers (pas toujours possible, n'est-ce pas ?), ou fait toi une librairie de calcul des réels en très haute précision (ce qui n'est que reculer pour mieux sauter, la précision ne pouvant évidemment pas être infinie), ou arrête de programmer : c'est un problème incontournable sans bricoler un peu.
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

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

Discussions similaires

  1. Problème avec une fonction date.
    Par kmayoyota dans le forum ASP
    Réponses: 8
    Dernier message: 09/09/2004, 12h33
  2. Problème avec la fonction findfirst ()
    Par Angelico dans le forum Windows
    Réponses: 3
    Dernier message: 05/08/2004, 20h40
  3. [Requete SQL en VBA] Problème avec la fonction FLOOR
    Par zubral dans le forum Langage SQL
    Réponses: 4
    Dernier message: 13/07/2004, 13h24
  4. Problème avec les fonctions
    Par jvachez dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 13/01/2004, 12h06
  5. [Postgresql]Problème avec les fonctions ...
    Par fet dans le forum Requêtes
    Réponses: 4
    Dernier message: 02/10/2003, 09h04

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