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 :

[D10.4] Vérifier les débordements sur un calcul


Sujet :

Langage Delphi

  1. #1
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 459
    Points : 3 090
    Points
    3 090
    Par défaut [D10.4] Vérifier les débordements sur un calcul
    Bonjour

    Je suis un Delphi 10.4.
    Dans un nouveau projet, j'additionne Double.MaxValue avec 100.
    Dans mon esprit, ça devrait remonter une erreur de dépassement mais il n'en est rien.
    J'ai coché les options qui semblent correspondre dans les options de projet mais ça ne change rien.

    Aurais-je raté la case à cocher qui va bien ?

  2. #2
    Membre confirmé Avatar de blonde
    Femme Profil pro
    Développeur Delphi
    Inscrit en
    Septembre 2003
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Septembre 2003
    Messages : 278
    Points : 477
    Points
    477
    Par défaut
    Il n'y aura pas de dépassement de la valeur sur cette somme, donc pas d'exception.
    Je ne sais effectivement pas comment "forcer" le dépassement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      var tutu := Double.MaxValue + 100  ;
      if tutu > Double.MaxValue then
        ShowMessage('dépassement')
      else
       if tutu = Double.MaxValue then
        ShowMessage('egal')
    --> affiche "egal"


    J'ai hâte de lire les réponses des experts.

  3. #3
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 459
    Points : 3 090
    Points
    3 090
    Par défaut
    Je pense que le code tel que tu l'écris force le type à Extended.
    Si on l'écrit comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TCalcul.Additionne(Valeur1, Valeur2: Double);
    var
      Somme: Double;
    begin
      try
        Somme := Valeur1 + Valeur2;
        DoOnNouveauTotal(Somme);
      except
        on E: Exception do
          DoOnErreurCalcul('ça marche pas');
      end;
    end;
    Somme est typé Double et ça ne devrait pas passer.

    Je confirme que ton "tutu" est bien en extended.

  4. #4
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    plusieurs choses à ce sujet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      var D1: Double := Double.MaxValue;
      var D2: Double := D1 + 100;
      if D1 = D2 then
        ShowMessage('Equals')
      else
        ShowMessage(D1.ToString + #13 + D2.ToString);
    end;
    on constate que D1 et D2 donnent la même valeur...comment est-ce possible ? Tout simplement car les flottants ont une représentation matricielle inexacte et qu'ajouter 100 à MaxValue (1.7976931348623157081e+308) reste dans la marge d'erreur....donc la valeur ne change pas.

    d'ailleurs retirer 100 ne change pas non plus la valeur de D2

    cf https://docwiki.embarcadero.com/RADS...ernes_(Delphi) pour le format Double

    pour avoir un EOverflow il faut dépasser un seuil que je ne connais pas en fait

    et sous FMX je pense que les exceptions des flottants sont désactivées car je ne vois aucune erreur sur D2 := D1 * D1 qui provoque par contre bien une exception sous VCL
    https://docwiki.embarcadero.com/Libr...stem.Set8087CW

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 097
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 097
    Points : 41 081
    Points
    41 081
    Billets dans le blog
    62
    Par défaut
    As-tu, avez-vous tenté d'utiliser l'unité System.Math et ses constantes maxdouble plutôt que double.maxvalue ?
    il y a aussi dans cette même unité un SetExceptions qui me fait de l'œil
    https://docwiki.embarcadero.com/Libr...en/System.Math

    Le lundi étant mon jour kiné, je ne vais pas me lancer dans un test mais, je lirai la suite de l'échange

  6. #6
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 459
    Points : 3 090
    Points
    3 090
    Par défaut
    Je reviens avec un peu de retard mais étant revenu au travail en temps partiel, je ne suis pas toujours dispo.

    Donc, il faudrait pouvoir découvrir quelle est cette limite qui déclencherait une exception. Intéressant et sans doute pas très compliqué à faire avec un while bien placé.

    Pour ce qui est du maxdouble en remplacement du Double.MaxValue, j'ose espérer que ça ne changerait pas la donne.

    Maintenant, que ça pose "problème" sur les valeurs flottantes, je veux bien mais je n'ai pas de EOverFlow non plus sur le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    var
      D1, D2, D3: Integer;
    begin
      D1 := Integer.MaxValue;
      D2 := D1;
      D3 := D1 + D2;
      ShowMessage(D3.ToString);
    end;
    Après correction de la coquille (affichage de D2 au lieu de D3), le résultat affiché donne -2

    Et là, j'aimerai mieux avoir une exception plutôt qu'un tel résultat potentiellement catastrophique


    Je progresse ! En ajoutant une directive de compilation ça déclenche bien un EIntOverFlow

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {$Q+}
    procedure TForm10.Button1Click(Sender: TObject);
    var
      D1, D2, D3: Integer;
    begin
      D1 := Integer.MaxValue;
      D2 := D1;
      D3 := D1 + D2;
      ShowMessage(D3.ToString);
    end;
    ---------------------------
    Project2
    ---------------------------
    Débordement d'entier.
    ---------------------------
    OK
    ---------------------------

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 563
    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 563
    Points : 25 165
    Points
    25 165
    Par défaut
    Pour ma part, je n'utilise pas la vérification des limites $Q+/{$OVERFLOWCHECKS ON} ou {$R+}/{$RANGECHECKS ON}

    J'ai un problème avec la pertinence du message de ERangeError par exemple, mais c'est valable aussi pour EIntOverFlow ... (que j'ai pour ma part sur des chaines trop longue)

    En prévention d'un collègue que l'activait en PROD sur ses projets, dans la lib commune, je désactivais localement la directive
    Et certains projets, au cas où, j'empêchais son activation !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // La "Vérification de débordement" est volontairement désactivée (normalement c'est le cas dans le projet) !
    // je préfère faire manuellement le controle uniquement lorsque c'est réellement nécessaire
    // cela permet de fournir un message plus clair que le banale "Erreur de vérification d'étendue"
    // en indiquant quelle propriétée a reçu une valeur hors limite ou dans quelle méthode se produit l'erreur
    {$IFOPT R+}
    {$MESSAGE ERROR 'AutomateLogistique_***_ProtocolClasses ne doit pas être compilé en RangeChecking car le code effectue ses propres contrôles pour améliorer les messages d erreur ! Veuillez retirer cette option du projet !!! '}
    {$R-}
    {$ENDIF RANGECHECKS}
    Car je prenais soin de faire des Accesseurs, j'ai en a des dizaines comme ça pour protéger des accès à une valeur en dehors d'un tableau type array[TEnum] ou des intervales comme 1..1000 .
    Ainsi l'exception ERangeError déclenchée était localisée, je savais où précisément l'erreur avait lieu et par une erreur générique qui sort comme ça de n'importe où

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    //------------------------------------------------------------------------------
    class procedure T***SetterAssistant.SetDropDestinationCode(const Value: string; Sender: TObject; var AMember: string);
    var
      V: string;
    begin
      if Length(Value) = LITTLE_***_RAW_DROP_DESTINATION_CODE then
        V := Value + string(StringOfChar(SPARE_ALPHA, SizeOf(T***RawDropDestinationCode) - LITTLE_***_RAW_DROP_DESTINATION_CODE))
      else
        V := Value;
     
      if Length(V) = SizeOf(T***RawDropDestinationCode) then
      begin
        if T***TypeConverter.IsValidString(V) then
          AMember := V
        else
          raise ERangeError.CreateFmt(ERR_INVALID_ALPHA_VALUE, [Value, Sender.ClassName()+'.DropDestinationCode']);
      end
      else
        raise ERangeError.CreateFmt(ERR_INVALID_ALPHA_LENGTH_VALUE, [Length(Value), Value, Sender.ClassName()+'.DropDestinationCode']);
    end;
     
    //------------------------------------------------------------------------------
    procedure T***FileMapDetailItem.SetDropNumber(const Value: T***DropNumber);
    begin
      if (Low(Value) <= Integer(Value)) and (Integer(Value) <= High(Value)) then
        FDropNumber := Value
      else
        raise ERangeError.CreateFmt(ERR_INVALID_NUMERIC_VALUE, [Value, ClassName()+'.DropNumber']);
    end;


    Pour ton calcul, je ferais pareil, je vérifierais les bornes avant d'effectuer un calcul qui pourrait provoquer une erreur
    Cela évite d'activer $Q+ dans toute une unité ou pire dans tous le projet et donc ajouter un tas de controle inutile la plupart du temps et ne protéger QUE le code sensible.

  8. #8
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 459
    Points : 3 090
    Points
    3 090
    Par défaut
    Vérifier les débordements par soi-même semble bien la meilleure solution !

    Bizarre que Delphi ne sache pas déclencher une exception sur les Double !

    Merci à tou(te)s

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

Discussions similaires

  1. Comment vérifier les statistiques sur les table d'un schéma
    Par juin29 dans le forum Administration
    Réponses: 1
    Dernier message: 17/06/2008, 16h55
  2. Grouper les contrôles sur une feuille de calcul
    Par stos dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 11/09/2007, 15h11
  3. Réponses: 6
    Dernier message: 10/05/2007, 16h24

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