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 :

Bug sur la fonction IncDay ? [Lazarus]


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    299
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 299
    Par défaut Bug sur la fonction IncDay ?
    Bonjour (et bonnes fêtes de noël !)

    Je suis en train de mettre au point une fonction de convertisseur entre le calendrier républicain et grégorien.
    Pour cela, je détermine le nombre de jours écoulés depuis le premier jour de ce calendrier (22/9/1793).
    Après avoir observé un écart par rapport aux valeurs attendues, je constate que :
    - DateToStr(IncDay(EncodeDate(1793,9,22),38817)) renvoie le 02/01/1900 (pour info, c'est le 12 nivose 108)
    - DateToStr(IncDay(EncodeDate(1793,9,22),38818)) renvoie le 04/01/1900 (alors que le nombre de jour à incrémenter n'a augmenté que d'un)

    Ma ou mes questions sont donc les suivantes :
    - Le 3 janvier 1900 a t-il vraiment existé ou un discontinum de l'espace temps est-il intervenu à ce moment là ? (les témoins manquent pour me confirmer cette assertion)
    - A moins qu'il n'y ait un trou dans la raquette sur la fonction IncDay de FreePascal ?
    (je précise que si on n'emploie pas cette fonction et qu'on code avec DateToStr(EncodeDate(1793,9,22)+38818)), on trouve bien le 03/01/1900)

    Merci par avance pour vos lumières sur ce bug avant-gardiste de l'an 1900...

  2. #2
    Responsable Pascal, Lazarus et Assembleur


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

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

    Informations forums :
    Inscription : Mars 2003
    Messages : 8 052
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    Étant donné que le type TDateTime est en fait un Double, il y a manifestement un arrondi qui entraîne l'erreur.

    Voici l'implémentation de IncDay dans l'unité DateUtils :
    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
    const
      TDateTimeEpsilon = 2.2204460493e-16;
     
    Procedure MaybeSkipTimeWarp(OldDate: TDateTime; var NewDate: TDateTime);
    begin
      if (OldDate>=0) and (NewDate<-TDateTimeEpsilon) then
        NewDate:=int(NewDate-1.0+TDateTimeEpsilon)-frac(1.0+frac(NewDate))
      else if (OldDate<=-1.0) and (NewDate>-1.0+TDateTimeEpsilon) then
        NewDate:=int(NewDate+1.0-TDateTimeEpsilon)+frac(1.0-abs(frac(1.0+NewDate)));
    end;
     
    Function IncDay(const AValue: TDateTime; const ANumberOfDays: Integer): TDateTime;
    begin
      Result:=AValue+ANumberOfDays;
      MaybeSkipTimeWarp(AValue,Result);
    end;
    Ceci dit, je ne reproduis pas ton erreur :
    38811 : 27-12-1899
    38812 : 28-12-1899
    38813 : 29-12-1899
    38814 : 30-12-1899
    38815 : 31-12-1899
    38816 : 01-01-1900
    38817 : 02-01-1900
    38818 : 03-01-1900
    38819 : 04-01-1900
    38820 : 05-01-1900
    38821 : 06-01-1900
    38822 : 07-01-1900
    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]

  3. #3
    Membre expérimenté
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    299
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 299
    Par défaut
    Merci pour ta réponse.
    Je précise mes versions utilisées : 3.0 RC1 pour Lazarus et 3.2.2 pour FPC.
    J'ai bien le même code que toi pour les 2 fonctions.
    Au final, le décalage ne semble pas lié à un problème d'arrondi puisqu'il continue les jours suivants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var iJour : integer;
    Begin
      memo2.Lines.Clear;
      for iJour := 38811 to 38822 do
        memo2.Lines.add(inttostr(iJour) + ' : ' + DateToStr(IncDay(EncodeDate(1793,9,22),iJour)));
    Donne :
    Nom : bug IncDay.JPG
Affichages : 157
Taille : 16,8 Ko

    Je vous promets que je n'ai abusé de rien pour les fêtes de noël mais si une personne obtient le même résultat, cela me rassurerait quelque peu même si ça ne résoudra pas le pb
    Du coup, j'attends un peu avant de créer un signalement de bug.

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 931
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 931
    Billets dans le blog
    6
    Par défaut
    Bonjour,
    Je n'ai pas abusé plus que toi et obtiens le même résultat !
    CodeTyphon 6.90 avec FreePascal 3.3.1 et cible Windows 64
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  5. #5
    Responsable Pascal, Lazarus et Assembleur


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

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

    Informations forums :
    Inscription : Mars 2003
    Messages : 8 052
    Billets dans le blog
    2
    Par défaut
    J'ai fait d'autres essais :

    • Lazarus 3.0 sous Windows 10 64 : date manquante ;
    • Lazarus 3.0 sous Garuda Linux 64 : aucun problème.

    Les deux OS sur la même machine (pas en virtualisation, en dual boot).



    [EDIT]
    Je suis allé jusqu'à l'an 2888, soit 400.000 itérations : l'erreur ne survient qu'au jour 38818 (et affecte tous les jours suivants).
    Ceci dit, les chances pour que l'on découvre ce bug étaient minces : on calcule rarement une date à partir de l'an 1793.
    [/EDIT]
    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]

  6. #6
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 931
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 931
    Billets dans le blog
    6
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      Memo1.Lines.Add(DaysBetween(-1.3, EncodeDate(1793,9,22)).ToString);
      Memo1.Lines.Add(DaysBetween(-0.3, EncodeDate(1793,9,22)).ToString);
      Memo1.Lines.Add(DaysBetween(+0.3, EncodeDate(1793,9,22)).ToString);
      Memo1.Lines.Add(DaysBetween(+1.3, EncodeDate(1793,9,22)).ToString);
    donne
    38812
    38813
    38813
    38814
    ce qui s'explique ainsi :
    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
    17
    18
    19
    20
    { ---------------------------------------------------------------------
        Period functions.
      ---------------------------------------------------------------------}
     
    {
      These functions are declared as approximate by Borland.
      A bit strange, since it can be calculated exactly ?
     
      -- No, because you need rounding or truncating (JM)
    }
     
     
    Function DateTimeDiff(const ANow, AThen: TDateTime): TDateTime;
    begin
      Result:= ANow - AThen;
      if (ANow>0) and (AThen<0) then
        Result:=Result-0.5
      else if (ANow<-1.0) and (AThen>-1.0) then
        Result:=Result+0.5;
    end;
    et par l'avertissement de la fonction MaybeSkipTimeWarp :
    TDateTime is not defined in the interval [-1.0..0.0[. Additionally, when
    negative the time part must be treated using its absolute value (0.25 always
    means "6 a.m.") -> skip the gap and convert the time part when crossing the
    gap -- and take care of rounding errors
    Reste à comprendre le décalage obtenu au passage :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Memo1.Lines.Add('Origine du TDateTime (30/12/1899) : ' + DateToStr(-0.8));
      Memo1.Lines.Add('Origine 22/09/1793 doit valoir -38814 : ' + Double(EncodeDate(1793,9,22)).ToString);
      Memo1.Lines.Add('Origine + 38817 doit valoir 3 : ' + (38817-38814).ToString);
      Memo1.Lines.Add('en passant par IncDay origine + 38817 vaut : ' + Double(IncDay(EncodeDate(1793,9,22),38817)).ToString);
      Memo1.Lines.Add('Origine + 38818 doit valoir 4 : ' + (38818-38814).ToString);
      Memo1.Lines.Add('en passant par IncDay origine + 38818 vaut : ' + Double(IncDay(EncodeDate(1793,9,22),38818)).ToString);
    qui fournit

    Origine du TDateTime (30/12/1899) : 30/12/1899
    Origine 22/09/1793 doit valoir -38814 : -38814
    Origine + 38817 doit valoir 3 : 3
    en passant par IncDay origine + 38817 vaut : 3
    Origine + 38818 doit valoir 4 : 4
    en passant par IncDay origine + 38818 vaut : 5
    [EDIT] Plus j'y comprends, moins j'y comprends... DateTimeDiff ne fonctionne pas pour les dates antérieures à l'origine...
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    299
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 299
    Par défaut
    Ouf, je me sens moins seul... Je suis effectivement sous Windows10 64.
    Ce qui me gênait, c'est que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Function IncDay(const AValue: TDateTime; const ANumberOfDays: Integer): TDateTime;
    begin
      Result:=AValue+ANumberOfDays;
    dans Dateutils aboutit à cette erreur et que si on remplace la fonction IncDay par ce qu'elle fait, autrement dit une simple somme DateToStr(EncodeDate(1793,9,22)+iJour), ça fonctionne.
    Du coup, j'ai focalisé mon attention sur la fonction MaybeSkipTimeWarp que j'ai dupliqué en local et j'ai pu localiser la ligne fautive qui est dans le Else de cette fonction et qui est bien exécutée dans mon exemple : NewDate:=int(NewDate+1.0-TDateTimeEpsilon)+frac(1.0-abs(frac(1.0+NewDate)));
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      dResult:=-38814+38817;  //AValue+ANumberOfDays;  =>dResult = 3
      MaybeSkipTimeWarp(-38814,dResult);
      showmessage(floattostr(dResult)); // Affichage : 3
     
      dResult:=-38814+38818;  //AValue+ANumberOfDays;  =>dResult = 4
      MaybeSkipTimeWarp(-38814,dResult);
      showmessage(floattostr(dResult)); //Affichage : 5
    Le problème semble donc être un problème de virgule flottante lié à l'utilisation de la fonction Frac... et au système d'exploitation !
    Les conséquences ne me semblent pas anodines car cette fonction est appelée dans toutes les fonction de type inc<...> (week, Hour, Minute, Second, Millisecond) et cela signifie que ces fonctions ne donnent pas toujours le résultat escompté dès lors qu'une date est antérieure au 01/01/1900.

    On fait quoi, maintenant ? Signalement auprès de l'équipe de dev ?

  8. #8
    Membre expérimenté
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    299
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 299
    Par défaut
    @Guesset, non, pour les dates sans heures, il y a bien 0 dans la partie décimale.

    Citation Envoyé par Alcatîz Voir le message
    J'ai fait d'autres essais :...
    Je suis allé jusqu'à l'an 2888, soit 400.000 itérations : l'erreur ne survient qu'au jour 38818 (et affecte tous les jours suivants).
    Ceci dit, les chances pour que l'on découvre ce bug étaient minces : on calcule rarement une date à partir de l'an 1793.
    [/EDIT]
    Oui, merci pour ces tests approfondis, je suis partiellement d'accord, il faut être généalogiste (un français sur 2 a déjà fait des recherches sur ses ancêtres) ET informaticien ET vouloir concilier les deux mondes

    Et puis, on peut extrapoler le problème de façon plus générale : toute fonction incday qui s'applique à une date antérieure au 01/01/1900 (même la veille) et qui après l'incrémentation passe après ce 1er janvier bugue (je viens de vérifier avec -1 pour la date et +4 et +5 dans l'incrément)

    @Tourlourou : Je pense que cette fonction MayBeSkipTimeWarp avait effectivement pour objectif de gérer cet intervalle -1.0..0.0, je suis de plus en plus convaincu qu'elle ne le fait pas bien

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

Discussions similaires

  1. Bug sur la fonction API ShGetValue
    Par yann458 dans le forum Windows
    Réponses: 2
    Dernier message: 22/10/2014, 17h41
  2. Bug sur la fonction financière TRIM ?
    Par pedromarga dans le forum Excel
    Réponses: 2
    Dernier message: 23/07/2011, 16h16
  3. [POO] Bug sur une fonction récursive : renvoit undefined
    Par zaboug dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 23/06/2008, 14h10
  4. Bug sur les fonctions virtuelles
    Par Anthony.Desvernois dans le forum C++
    Réponses: 4
    Dernier message: 28/01/2008, 17h30
  5. Rapport de bug sur les fonctions de XDebug
    Par lryo79 dans le forum Zend Studio
    Réponses: 8
    Dernier message: 14/06/2007, 15h35

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