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

C Discussion :

Multiplication et overflow


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Ingénieur en électronique
    Inscrit en
    Septembre 2004
    Messages
    419
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur en électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 419
    Points : 333
    Points
    333
    Par défaut Multiplication et overflow
    Bonjour , je réalise sur un microcontroleur une multiplication

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    unsigned int a,b,c; 
     
    a=900;
    b=90 ;
     
    c=a*b;//c=81000= 0x1 3C68 >deviens> 0x3C68 = 15464

    J'aimerais savoir s'il existe une fonction qui fonctionne sur tous les micro-contrôleurs pour détecter cette erreur.

    Merci d'avance

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    non, ca s'appelle un integer overflow, et c'est inhérent au fait que les entiers ont une représentation finie.
    Par contre, tu peux souvent savoir que tu va subir l'erreur
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par paterson Voir le message
    J'aimerais savoir s'il existe une fonction qui fonctionne sur tous les microcontroleur pour détecter cette erreur.
    Bonjour

    On peut tricher en redéfinissant sa propre multiplication qui intègrera un contrôle du résultat

    Code c : 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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #include <stdio.h> 
    #include <stdlib.h>
     
    int mult(int x, int y, int *err)
    {
    	int res=x*y;
    	if (err)
    	{
    		if (x) (*err)=(res / x) == y ?0 :1;
    		else {
    			if (y) (*err)=(res / y) == x ?0 :1;
    			else (*err)=0;
    		}
    	}
     
    	return res;
    }
     
    int main(int argc, char *argv[]) 
    { 
    	int x, y, res;
    	int err;
     
    	x=10;
    	y=20;
    	res=mult(x, y, NULL);
    	printf("%d * %d=%d\n", x, y, res);
     
    	x=10;
    	y=20;
    	res=mult(x, y, &err);
    	printf("%d * %d=%d (err=%d)\n", x, y, res, err);
     
    	x=9000000;
    	y=900000;
    	res=mult(x, y, &err);
    	printf("%d * %d=%d (err=%d)\n", x, y, res, err);
    }
    ...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    @Sve@r: N'y a-t-il pas un truc qui cloche avec ton code?

    En plus, de la valeur de retour qui vaut false (0) si tout c'est bien passé.
    Et aussi de dire que "tout" c'est bien passé (<- à ta façon) lorsque err est NULL.

    Si x vaut 0, alors res vaut 0: pas la peine de tester la valeur de y dans ce cas.

  5. #5
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 187
    Points : 11 568
    Points
    11 568
    Par défaut
    Citation Envoyé par paterson Voir le message
    J'aimerais savoir s'il existe une fonction qui fonctionne sur tous les microcontroleur pour détecter cette erreur.
    Tu veux détecter un overflow lors d'un calcul arithmétique ?
    Bien sur que l'on peut, comment penses tu que l'on fais lorsqu'on bosse en assembleur ?

    Dans ton micro, il y a forcément un registre qui t'indique si une opération arithmétique a débordée.
    Sur le micro ATMEGA328P (Arduino UNO) c'est normalement dans le registre SREG
    Sur le micro PIC18F4550 c'est le registre STATUS REGISTER
    Sur le micro MSP430G2253 (LaunchPad) c'est le registre SR

    Par contre, je n'arrive pas à comprendre pourquoi tu souhaites faire ça ? Ton micro est une calculette ?
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par foetus Voir le message
    @Sve@r: N'y a-t-il pas un truc qui cloche avec ton code?

    Si x vaut 0, alors res vaut 0: pas la peine de tester la valeur de y dans ce cas.
    La structure de tests pourrait être plus claire peut-être. Dans le main, j'ai un doute sur l'affichage de err.

    Citation Envoyé par foetus Voir le message
    En plus, de la valeur de retour qui vaut false (0) si tout c'est bien passé.
    Tu as déjà essayé de faire echo $? sous Unix pour connaitre la valeur de retour d'une commande ?

    Citation Envoyé par foetus Voir le message
    Et aussi de dire que "tout" c'est bien passé (<- à ta façon) lorsque err est NULL.
    T'as déjà essayé de déréférencer NULL pour y écrire ton code d'erreur toi ????

  7. #7
    Membre éclairé
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Points : 870
    Points
    870
    Par défaut
    Citation Envoyé par Sve@r
    On peut tricher en redéfinissant sa propre multiplication qui intègrera un contrôle du résultat

    Code c : 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
    #include <stdio.h> 
    #include <stdlib.h>
     
    int mult(int x, int y, int *err)
    {
    	int res=x*y;
    	if (err)
    	{
    		if (x) (*err)=(res / x) == y ?0 :1;
    		else {
    			if (y) (*err)=(res / y) == x ?0 :1;
    			else (*err)=0;
    		}
    	}
     
    	return res;
    }
    Ce code est buggué car il contient un UB (undefined behavior).
    Tu utilises des entiers signés et l’overflow sur les entiers signés est un UB (sur les entiers non-signé, c'est défini par contre). Dès le moment où tu as fait la multiplication, c'est trop tard.

    C'est comme faire du code de ce genre :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    static void __devexit agnx_pci_remove (struct pci_dev *pdev)
    {
      struct ieee80211_hw *dev = pci_get_drvdata(pdev);
      struct agnx_priv *priv = dev->priv; 
     
      if (!dev) return;
     
      ... do stuff using dev ...
    }
    C’est buggué car tu as déjà déclenché ton UB avant le test et le compilateur peut virer ton test.

    Les UB ça peut être source de bug très sioux, car ça peut dépendre des options d'optimisations, de ton compilateur voire même de la version de ton compilateur (j'ai déjà été confronté à une SEGFAULT qui ne se produisait qu'avec clang + optimisations, cf. ici pour ceux que ça intéressent).

    Pour ceux qui veulent en savoir plus sur les UB, je vous conseille deux séries de trois articles :
    La série de Chris Lattner :
    - What Every C Programmer Should Know About Undefined Behavior #1/3
    - What Every C Programmer Should Know About Undefined Behavior #2/3
    - What Every C Programmer Should Know About Undefined Behavior #3/3
    Et la série de John Regehr (qui a un très bon blog, je vous le recommande chaudement) :
    - A Guide to Undefined Behavior in C and C++, Part 1
    - A Guide to Undefined Behavior in C and C++, Part 2
    - A Guide to Undefined Behavior in C and C++, Part 3


    Pour en revenir au sujet (comment tester l’overflow) après cette digression sur les UB, il y a plusieurs façons qui dépendent de tes contraintes*:
    - How Should You Write a Fast Integer Overflow Check?
    - Catching Integer Overflows in C

    Cela dit, si l‘on se limite aux entier non-signés (ce que l'auteur du sujet utilise dans son exemple), la situation est plus simple car l‘overflow est définie par le standard (wrap-around). Du coup, pour la détection on peut se contenter de faire quelque chose du genre (à tester, surtout sur les cas limites)*:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    unsigned mul(unsigned x, unsigned y, int *err)
    {
        unsigned res = x * y;
     
        if (err) {
            *err = (res < x || res < y);
        }
     
        return res;
    }

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Personnellement en non-signé, je ferais quand même une division pour vérifier, plutôt qu'un test d'infériorité.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre éclairé
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Points : 870
    Points
    870
    Par défaut
    Citation Envoyé par Médinoc
    Personnellement en non-signé, je ferais quand même une division pour vérifier, plutôt qu'un test d'infériorité.
    Oui, c'est peut-être plus fiable que le test d'infériorité (j'ai pas testé le comportement avec des valeurs limites).

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par foetus Voir le message
    En plus, de la valeur de retour qui vaut false (0) si tout c'est bien passé.
    C'est une habitude venue du shell où l'état d'une commande vaut 0 quand la commande s'est bien passée. C'est d'ailleurs plutôt logique: quand quelque chose se passe bien, pas besoin d'expliciter (=> autant utiliser alors 0). En revanche, si quelque chose se passe mal, alors t'as toute la gamme des positifs disponibles pour indiquer en finesse le détail de ce qui a cloché (1=truc qui ne s'ouvre pas, 2=chose qui n'est pas alloué, 3=machin pas connecté, etc...).
    Et c'est parfois aussi le cas en C (strcmp() qui vaut 0 quand c'est égal)...

    Citation Envoyé par foetus Voir le message
    Et aussi de dire que "tout" c'est bien passé (<- à ta façon) lorsque err est NULL.
    Non t'as pas bien saisi le principe: si l'appelant veut un retour des erreurs éventuelles il passe alors l'adresse d'une variable destinée à stocker ce retour. En revanche s'il ne veut pas s'en préoccuper, alors il passe NULL et donc considèrera (par défaut) que l'opération se passe bien.

    Citation Envoyé par foetus Voir le message
    Si x vaut 0, alors res vaut 0: pas la peine de tester la valeur de y dans ce cas.
    Exact - Fameux manque d'à propos à ce sujet. Mais c'était à 23h et j'étais pas mal crevé
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Réponses: 87
    Dernier message: 06/07/2011, 15h33
  2. [Overflow] Test pour la multiplication
    Par Nanoc dans le forum C++
    Réponses: 10
    Dernier message: 05/09/2008, 21h49
  3. formulaire choix multiple
    Par pram dans le forum XMLRAD
    Réponses: 6
    Dernier message: 02/02/2003, 18h59
  4. Création multiple table paradox dans le code
    Par scarabee dans le forum C++Builder
    Réponses: 8
    Dernier message: 30/10/2002, 10h17
  5. Réponses: 6
    Dernier message: 25/03/2002, 21h11

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