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

x86 32-bits / 64-bits Assembleur Discussion :

[GCC] Calcul du résidu modulo n du produit x*y provoque un plantage


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut [GCC] Calcul du résidu modulo n du produit x*y provoque un plantage
    Bonjour

    Contexte : utilisation d’un programme en assembleur au sein d’un programme en C++.
    Syntaxe AT&T (gcc),

    Le programme suivant calcule le résidu modulo n du produit x*y
    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
     
    // output : (x*y)%n
    uint64_t mulmod64(uint64_t x, uint64_t y, uint64_t n)
    {
       uint64_t z;
       __asm__ __volatile__(
          " mul %[y] ;"
          " div %[n] ;"
          :    "=d" (z)
          : [x] "a" (x),
            [y] "r" (y),
            [n] "r" (n)
          : "cc"
       );
       return(z);
    }
    Il fonctionne bien pour des valeurs vérifiant x*y / n < 2^64

    Dans le cas contraire, je m’attendais à un problème mais pas à ça !

    Mon espoir était une valeur correcte du résidu et une valeur tronquée du quotient mais un résultat complètement faux ne m’aurait pas choqué.

    En fait le programme PLANTE sans gestion d’erreur : il semble complètement perdu au milieu d’une boucle infinie …

    J’aimerais savoir si ce problème est reproductible en syntaxe AT&T aussi bien qu’en syntaxe Intel.
    Je suis loin d'être un expert en programmation et il est possible que je sois passé a côté d’un truc important.

    Merci d’avance pour une réponse.

  2. #2
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    La syntaxe n'a rien n'a voir la dedans (par défaut GCC est en syntaxe AT&T).

    Sinon pour ton soucis ,je n'ai pas compris ce qui plante ?
    Par contre les division par zero pose soucis.

  3. #3
    Membre régulier
    Homme Profil pro
    retraité
    Inscrit en
    Avril 2019
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Avril 2019
    Messages : 49
    Points : 70
    Points
    70
    Par défaut
    Bonsoir.
    Dans la documentation il est indiqué que le quotient ne peut pas être > 2 puissance 64 -1
    Or si vous multiplier un grand nombre par un grand nombre le résultat est stocké dans RAX et RDX.
    Et si vous diviser ce résultat par un petit nombre, le quotient est > 2 puissance 64 -1 et ça le processeur n'aime pas du tout :
    Exemple en assembleur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       mov rax,12345678912345678
        mov rbx,1234
        mov rdx,0
        mul rbx
        mov rcx,12
        div rcx
    Erreur : Floating point exception(core dumped)
    Par contre ceci est correct
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        mov rax,12345678912345678
        mov rbx,12345678
        mov rdx,0
        mul rbx
        mov rcx,123333333
        div rcx
    Résultat :
    Valeur decimale du registre : 1235803596933604
    Valeur decimale du registre : 4257552

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Merci à tous les deux

    @Kannagi : « division par zéro ». Ce n’est pas le problème (normalement on évite de faire des calculs modulo 0 ).
    Si tu ne vois pas ce qui plante, essaie le programme, ce n’est pas long.

    @vincent Boulou : je sais bien que le problème survient quand x*y / n < 2^64 n’est pas vérifié (c’est ce que j’ai écrit). Ce qui me gêne, c’est la réaction de mon programme.

    Dans ton exemple (syntaxe Intel), ton programme écrit : <Erreur : Floating point exception(core dumped)> .
    C’est un message que je n’ai pas : mon programme se contente de boucler indéfiniment et c'est cela qui me gêne.

    En fait, quand je parlais de « syntaxe » j'aurais mieux fait de parler de compilateurs (gcc / Visual / etc.).

    De plus, tu dis « Dans la documentation …. ». De quelle documentation parles-tu ? Peux tu me dire où la trouver ?

  5. #5
    Membre régulier
    Homme Profil pro
    retraité
    Inscrit en
    Avril 2019
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Avril 2019
    Messages : 49
    Points : 70
    Points
    70
    Par défaut
    Bonjour.
    Le message d'erreur que j'ai indiqué est le message donné par l'assembleur que j'ai utilisé.
    Dans ton cas, bien que les compilateurs C ou C++ soient intelligents, ils ne sont pas capables à mon avis de détecter une erreur commise dans l'ajout d'instructions en assembleur. Donc dans ce cas, la suite de l’exécution du programme peut être n'importe quoi !!
    Il faudrait regarder la génération assembleur issu de ton compilateur pour voir ce que fait C++ dans ce cas.
    Avec la chaleur, j'ai réfléchi à ton problème cette nuit et normalement le compilateur C++ doit proposer une solution correcte au calcul modulo n (codée en C++) pour toutes les valeurs ou signaler correctement l'erreur. Pourquoi veut tu utiliser l'assembleur dans ce cas ?
    Il est aussi possible de calculer d'abord chaque valeur modulo N puis de faire la multiplication et de recalculer le résultat modulo n et ceci sans dépassement de capacité je pense. Mais c'est à vérifier.
    Autrement il ne reste plus qu'à écrire une division des registres rdx -rax par rcx et obtenir le quotient dans 2 registres et le reste dans un 3ième registre.
    ou l'écrire en C++
    Pour la documentation il y a la doc Intel : https://www.intel.com/content/www/us...l#three-volume

    ou plus simplement ceci : https://www.gladir.com/LEXIQUE/ASM/div.htm

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour Vincent

    Merci pour les liens. Je n’avais pas compris que tu programmais directement en assembleur. C’est sûr que dans ce cas les messages d’erreurs doivent être plus « pointus ».

    1) quand on désassemble (x*y)% n , on voit que C++ ne fait pas dans le détail : il suppose que x*y < 2^64 et met le registre rdx à 0 avant de diviser par n. Donc pas d’erreur, mais le résultat est faux dès que x*y ≥ 2^64,

    2) J’utilise l’assembleur pour avoir une réponse correcte. L’alternative est de calculer (x*y)% n en 128 bits (avec Boost par exemple) mais alors le calcul est beaucoup plus lent. Comme je l’utilise pour calculer (x^p)%n (qui lui même me servira pour etc.), la vitesse est un facteur important.

    3) mulmod64(x,y,n) est correct dès que x < n OU y < n. Donc, pour mon utilisation, il fonctionne correctement. Ma question est donc d’ordre général et ne concerne pas la résolution d’un problème personnel.

    D’habitude quand un problème survient on a droit à un message d’erreur, plus ou moins clair, mais au moins le programme s’arrête et on peut déboguer. Je voulais savoir si ce plantage (le programme ne s’arrête pas) était propre à ma configuration : Windows + Code::Blocks + compilateur TDM64 (gcc 64 bits) ou bien comme tu le dis à propos des compilateurs
    ils ne sont pas capables à mon avis de détecter une erreur commise dans l'ajout d'instructions en assembleur
    C’est pourquoi il me semble intéressant d’avoir les résultats d’expériences avec différentes configurations. Ce n’est pas très long. Comme tu a pris le temps de me répondre, peut-être pourrais-tu aussi prendre le temps d’initier cette séries d’expériences ? Quoi qu’il en soit, merci encore,

  7. #7
    Membre régulier
    Homme Profil pro
    retraité
    Inscrit en
    Avril 2019
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Avril 2019
    Messages : 49
    Points : 70
    Points
    70
    Par défaut
    Bonsoir.
    Je ne suis pas un spécialiste du C mais j'ai essayé de voir les résultats dans un petit programme avec que des instructions en C (compilateur gcc sous windows 11):

    x=2900000000000000005 f=100 y=29 (x*f)=-5147905179352825356 (x*f)%y=0
    x=2900000000000000005 f=100 y=29 x%y=5 f%y=13 ((x%y)*(f%y))%y=7

    Dans ce cas, ni le compilateur ni lors de l’exécution il n'y a de signalement d'erreur !! alors que le résultat de la première ligne est manifestement faux.

    Je vais regarder comment appeler des instructions en assembleur depuis le programme C et je vais tester.

    Voici le programme en C :
    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
    #include <stdio.h>
    int main(void) {
       long long int x = 2900000000000000005;
       long long int y = 29;
       long long int f = 100;
       long long int z = 0;
       long long int z1 = 0;
       long long int z2 = 0;
       z1=x*f;
       z=z1%y;
     
       printf("x=%lli f=%lli y=%lli (x*f)=%lli (x*f)%y=%lli\n",x,f,y,x*f,z);
     
        z1=x%y;
        z2=f%y;
        z=(z1*z2)%y;
       printf("x=%lli f=%lli y=%lli x%y=%lli f%y=%lli ((x%y)*(f%y))%y=%lli \n",x,f,y,x%y,f%y,z);
     
    }

  8. #8
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par vincent Boulou Voir le message
    Bonsoir.
    Dans ce cas, ni le compilateur ni lors de l’exécution il n'y a de signalement d'erreur !! alors que le résultat de la première ligne est manifestement faux.
    Je vois pas pourquoi le compilateur planterai surtout en C , ou le compilateur laissera passer pas mal de chose ,meme si ça plante à l’exécution.

  9. #9
    Membre régulier
    Homme Profil pro
    retraité
    Inscrit en
    Avril 2019
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Avril 2019
    Messages : 49
    Points : 70
    Points
    70
    Par défaut
    Citation Envoyé par Kannagi Voir le message
    Je vois pas pourquoi le compilateur planterai surtout en C , ou le compilateur laissera passer pas mal de chose ,meme si ça plante à l’exécution.
    Oui mais là, ça ne plante même pas à l’exécution !! C'est quand même grave que sur une simple multiplication division, le résultat soit faux pour des valeurs importantes. Cela a dû entrainer pas mal de bugs !!

    Bon mon test n'est pas bon car en mettant l'option S2 pour avoir le généré assembleur je me suis rendu compte que mon compilateur était encore en 32 bits.
    Il faut donc que je réinstalle gcc 64 bits sur windows 11.

    (Autre chose : le généré assembleur peut-il être sorti avec la syntaxe intel ? doit peut être y avoir une option)















    ,

  10. #10
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par vincent Boulou Voir le message
    C'est quand même grave que sur une simple multiplication division, le résultat soit faux pour des valeurs importantes. Cela a dû entrainer pas mal de bugs !!
    Le C propose des UB (Undefined Behavior) , pour certain cas notamment l'overflow !
    Donc non , c'est tout à fait normal (j'ai testé sur 64 bits).

    Il faut juste regarder le résultat en hexa , c'est flagrant !
    En hexa : 0x283EDEA2 98A20005 = 2900000000000000005

    De base , on sait que si on fait x16 , ça fera un décalage sur la gauche de 4 bits , donc un overflow (et on l'a carrémennt sur un x100).

    Si tu utilise une calculatrice quand je fait 2900000000000000005×100 , en hexa , ça me donne : 0xF B88E F783 9F48 01F4 , soit 17*4bits , ce qui donne le résultat sur 68 bits !

    Si tu as du mal avec l'hexa ,je te met valeux max /ta valeur , c'est assez flagrand :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    18 446 744 073 709 551 615 //valeux max (en unsigned, sinon c'est la moitié en signé )
    _2 900 000 000 000 000 005 //valeur actuel
    Donc sur les grosses valeurs , on utilise des libs pour gérer des gros nombre (qui utilise sûrement le binary coded decimal pour gérer des gros nombre ) , sauf si la précision n'est pas ultra important et on utilise les doubles.

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour

    Comme je le disais dans mon précédent message
    Quand on désassemble (x*y) % n , on voit que C++ ne fait pas dans le détail : il suppose que x*y < 2^64 et met le registre rdx à 0 avant de diviser par n. Donc pas d’erreur, mais le résultat est faux dès que x*y ≥ 2^64.
    Il est donc normal que le programme en C++
    1) ne plante pas
    2) donne un résultat faux dès que x*y >= 2^64

    Le problème n’est pas là. Il est, du moins dans ma configuration, dans la non prise en charge des exceptions en assembleur (ici #DE) par le compilateur C++. C’est uniquement cela qui cause le plantage.

    Je réitère ma question : y a-t-il des configurations où cette prise en charge existe ou bien est-ce général ?

  12. #12
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par serge17 Voir le message
    Je réitère ma question : y a-t-il des configurations où cette prise en charge existe ou bien est-ce général ?
    Alors il faut savoir compilateur C ou C++ ?
    Dans les deux cas , le compilateur fait ce qu'il veut , s'il veut le gérer ou pas, mais je pense que aucun se casse la tête de gérer ce genre d’exception !
    Mais si ta question est est ce que le langage gère ce genre d'exception , la réponse est non ,c'est trop spécifique au CPU (certain CPU ne renverra "rien" en cas d'overflow , au mieux un bit de flag).

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Compilateur C++ : TDM64 (gcc 64 bits)

    Dans la doc, il est dit que si le quotient ne tient pas dans le registre indiqué, le CPU envoi le bit-flag d’overflow #DE. Que le compilateur C++ n’en tienne pas compte est une chose. Mais, en général, un overflow conduit à des résultats faux mais ne provoque pas de plantage ; je me trompe ?

    Là, le CPU semble coincé dans une boucle infinie … Y a-t-il d’autres cas de ce genre ?

  14. #14
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Oui , mais ton plantage n'est peut être pas du a la division/modulo , preuve en est , si tu le fait en C++ , ça plante pas !

    Ton code asm doit modifier un registre utiliser par le compilo , ce qui cause ce 'plantage" je pense.

  15. #15
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour Kannagi

    Tes connaissances en informatique sont probablement très largement supérieures aux miennes. Le problème c’est que tu interviens sur un grand nombre de sujets (merci à toi) et je ne parle même pas de ton boulot rémunéré !

    Donc, sans mettre en doute tes compétences, je dis que sur le coup tes réponses ne sont pas au niveau : il faudrait que tu prennes 5 minutes pour regarder le problème sérieusement.

    Oui , mais ton plantage n'est peut être pas du a la division/modulo
    Si, il l’est. On peut même fabriquer un plantage avec une simple division (sans multiplication préalable) : il suffit de faire la division sans mettre le registre rdx à 0. Il contient alors n’importe quoi et en général une valeur beaucoup trop grande.

    preuve en est , si tu le fait en C++ , ça plante pas !
    Si tu as lu ce que j’ai écrit plus haut, C++ met le registre rdx à 0 avant toute division. Il ne peut donc jamais planter ; il donne juste un résultat faux si on a besoin de rdx (cas de la multiplication préalable avec des valeurs "correctes").

    Ton code asm doit modifier un registre utiliser par le compilo
    Regarde le programme : tu vois bien que ce n’est pas le cas. Si tu as un doute rédiges en un toi même en prenant toutes les précautions.

    Ma question initiale à évoluée. Ce n’est plus tellement le fait que le compilateur C++ ne tienne pas compte des overflows (je me suis fait une raison) ; c’est le fait qu’à cause d’une overflow, le CPU ne se contente pas de donner un résulte faux ou d’interrompre le programme : il plante.

    PS : tout cela ne concerne que l’asm étendu dans un programme C++. Un programme rédigé directement en assembleur semble réagir différemment aux overflows (cf. le premier message de vincent Boulou )

    Merci pour ton implication.

  16. #16
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Merci , disons que j'ai pas trop compris le soucis , je viens de relire , tu demande si la division par 0 plante ?
    Si c'est le cas , oui , la division par 0 (sur le x86) créer une interruption , qui a tendance du coup à "planté" le programme (enfin c'est l'OS qui le décide ).

  17. #17
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    tu demande si la division par 0 plante ?
    Ben non ! je ne suis pas un expert, mais quand même ! On divise par n qui est le modulo (donc pas nul).

    On tourne en rond. C'était ta première réponse et j'ai répondu que non ; tu n'as vraiment pas 5 minutes ?

    Ajout : je me suis amusé à programmer en assembleur une fonction divise et je l'ai utilisée pour faire une division par 0.
    Résultat : le CPU ne plante pas. Il sort avec le message d'erreur
    Process returned -1073741676 (0xC0000094)
    c’est-à-dire Integer Divide by Zero Exception.

    Le compilateur C++ est donc capable de gérer cette exception, contrairement au dépassement de capacité de mon problème.

  18. #18
    Membre régulier
    Homme Profil pro
    retraité
    Inscrit en
    Avril 2019
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Avril 2019
    Messages : 49
    Points : 70
    Points
    70
    Par défaut
    Bonjour serge17.
    J'ai essayé de faire des tests en 64 bits mais je n'y suis pas arrivé car installer gcc pour avoir un exécutable 64 bits sur windows est une galère.
    J'ai donc essayé d'utiliser le compilateur C de microsoft 64 bits mais hélas il ne gère pas l'assembleur inline.
    J'ai donc fait un test avec le compilateur C microsoft 32 bits avec ce programme :
    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
     
    #include <stdio.h>
     int testFctasm(  int x1,   int f1,  int  y1)
    {
    __asm {
       mov eax,x1
       mov ebx,f1
       mul ebx        // met à jour edx
       mov ebx,y1
       div ebx        // divise eax,edx
       mov eax,edx    // retourne le reste
    }
    }
     
    int main(void) {
       int x = 2900000005;
       int y = 29;
       int f = 100;
       int a = 0;
     
       a =testFctasm(x,f,y);
     
       printf("a =  %u \n", a);     
     
     
    }

    Il donne un résultat correct pour des valeurs de X petites mais pour de grandes valeurs il n'y a aucun résultat ni signalement d'erreur.
    De plus le programme ne rend la main qu'après plusieurs secondes donc je suspecte qu'il boucle et qu'il est interrompu par un mécanisme de sécurité de windows11

    Pour un test avec gcc 32 bits, il faut que j'apprenne la syntaxe des instructions assembleur inline car cela ne semble pas simple !!
    Si cela peut t'apporter un début de réponse à ton interrogation.
    Cordialement.

  19. #19
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour Vincent

    J’ai donné mon test en 64 bits car mon compilateur C++ est un 64 bits mais ton test en 32 bits est tout à fait suffisant. Il y un overflow dès que le quotient de x*y par n ne tient pas dans le registre de destination : rax en 64 bits, eax en 32 bits et ax en 16 bits.

    Avec les valeurs données dans ton exemple, ton programme fonctionne. Le « même » programme en 16 bits (eax→ ax, ebx →bx et edx → dx) plantera avec ces mêmes valeurs.

    Dès mon premier message, j’ai dit que je savais qu’il y aurait un problème quand le quotient est trop gros mais je ne savais pas lequel. La gestion des overflows a toujours été de la responsabilité du programmeur (le logiciel se contente de les signaler). Mais j’ai été surpris par le plantage du CPU : je ne m’y attendais pas du tout. D’après la doc (que tu m’a indiquée), l’assembleur signale l’overflow dans le bit-flag #DE ; mais je ne sais pas quoi en faire, car le programme semble planter dans la division : il ne passe donc pas à l’instruction suivante qui pourrait être du genre : « si DE = 1 alors ... »

    PS :
    De plus le programme ne rend la main qu'après plusieurs secondes donc je suspecte qu'il boucle et qu'il est interrompu par un mécanisme de sécurité de windows11
    J’ai laissé le plantage pendant 60 secondes et je n’ai pas eu d’interruption : mais je n’ai que Windows 10 …

    Pour un test avec gcc 32 bits, il faut que j'apprenne la syntaxe des instructions assembleur inline car cela ne semble pas simple !!
    Les syntaxes AT&T et Intel sont un peu différentes : ceux qui sont à l’aise avec l’une trouvent que l’autre est compliquée.
    Tu peux voir https://asm.developpez.com/cours/asminline/ et http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO

  20. #20
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2012
    Messages : 72
    Points : 48
    Points
    48
    Par défaut
    Bonjour Vincent (suite)

    On pose b = 2^64 (en 64 bits). On suppose que 0 < x < b (idem pour y)
    Après la multiplication de x par y on a x*y = rdx*b + rax
    La condition x*y/n < b (nécessaire pour que tout se passe bien) est équivalente à rdx < n.
    Comme on fait du calcul modulo n, on peut remplacer rdx par rdx%n quand elle n’est pas vérifiée.
    D’où le programme modifié suivant :
    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
    uint64_t mulmod64_checked(uint64_t x, uint64_t y, uint64_t n)
    {
       uint64_t z;
       __asm__ __volatile__(
          " mul %[y] ;"
          " CMP %%rdx, %[n] ;"
          " JA 0f;"                  // jump if n - rdx > 0
          " mov %%rax, %[y] ;"       // save rax
          " mov %%rdx, %%rax ;"      // prépare la division ...
          " mov $0, %%rdx ;"         // ... de rdx par n
          " div %[n] ;"              // new-rdx = old-rdx % n;
          " mov %[y], %%rax ;"       // restore rax
       "0 : div %[n] ;"              // rdx < n
          " mov %%rdx, %%rax ;"
          :    "=a" (z)
          : [x] "a" (x),
            [y] "r" (y),
            [n] "r" (n)
          : "cc", "%rdx"
       );
       return(z);
    }

    Le programme initial fonctionne parfaitement si x < n OU y < n. Quand on fait du calcul modulo n à la chaîne c’est forcément vérifié ; inutile de compliquer. Mais pour un calcul occasionnel, le programme complété peut être utile.

    Il est à remarquer que si n² > b, alors le calcul ( x%n * y%n )%n ne donne pas nécessairement un résultat correct.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Calculer des fournisseurs en fonction de produits
    Par Helpo dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 19/04/2017, 09h08
  2. Réponses: 6
    Dernier message: 08/02/2015, 17h26
  3. [z/OS] Calcul d'un MODULO
    Par Petit scarabé dans le forum Cobol
    Réponses: 7
    Dernier message: 04/06/2009, 12h30
  4. simplification calcul puissance et modulo
    Par Gotman-B dans le forum Delphi
    Réponses: 5
    Dernier message: 23/05/2007, 18h23
  5. Code produit par gcc 3.2.3 / 3.4.3
    Par Neysa dans le forum x86 32-bits / 64-bits
    Réponses: 3
    Dernier message: 04/07/2006, 13h16

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