échange nombre, sans variable intermédiaire.
Répondre à la discussion
Affichage des résultats 1 à 30 sur 30

échange nombre, sans variable intermédiaire.



  1. #1
    Olympe02

    échange nombre, sans variable intermédiaire.


    ------

    Bonsoir,

    J'essaye de programmer cet algorithme. Sur ce chapitre, j'ai appris à échanger les variables, déclarer/affecter une variable, afficher du texte, les chaines de caractère (string), les opérations. Avec le langage de programmation C++
    Pouvez-vous m'aider svp^ Je n'arrive pas à comprendre la consigne

    Voici l'énoncé:
    Ecrire un programme qui demande à l'utilisateur deux nombres, les affiches, les échange, et les ré-affiche, après échange, mais sans utiliser de variable intermédiaire. On pourra utiliser une addiction et une soustraction pour ne rien perdre.
    Voici mon code:
    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
        int a, b, c; // déclarer les variables
        cout << "Saisir deux nombres" << endl; // afficher les variables
        cin >> a >> b; // saisir les nombres
        c=b;
        b=a;
        a=c;
    
    
    
        return 0;
    }
    Merci d'avance et bonne soirée

    -----

  2. #2
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Bonjour,

    si vous ne suivez pas l'énoncé ...

    1 ) demande à l'utilisateur deux nombres, 2 ) les affiches, 3 ) les échange, 4 ) les ré-affiche
    et ce , sans la variable c que vous avez déclarée

    Pour le swap ( l'échange ) , il faut tâtonner un peu mais avec + et - , et sachant qu'il faut au moins 3 opérations , c'est vite fait

    Voilà une solution mais il y en a plusieurs :
    // a=A
    // b=B

    a += b ;
    // ( a == A+B )

    b = ( a - b ) ;
    // ( b == A+B-B == A )

    a -= b ;
    // ( a == A+B-A == B )

    Trouvez en une autre. Ca ne sert à rien d'utiliser celle ci, votre exercice est le seul intérêt de ce devoir.

    Reprenez maintenant votre programme en suivant les instructions de l'énoncé dans l'ordre , utilisez votre variante de swap et testez le ( jusqu'à ce que ça "marche" ! )


  3. #3
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Très élégant ce petit tour de maths, je ne connaissais pas. Très bien comme exo, mais en vrai j'utiliserais une troisième variable, ça me paraît plus clair...

    Une question à ce propos à un spécialiste: Si on applique ça sur du float ou double, est-ce que on se retrouvera toujours avec exactement les mêmes valeurs qu'au début (mais permutées bien sûr)? Je pose la question parce que à ma connaissance les dit types de variables ne permettent pas toujours de stocker exactement la valeur qu'on veut (d'où l'interdiction des comparaisons genre ==), alors en faisant les calculs ne risque-t-on pas en quelque sorte des erreurs d'"arrondis"? (Oui, c'est tordu comme question.)

  4. #4
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    En effet, avec d'autres types que l'entier, il y a une prise de risques. Quoique cela s'améliore : il y a très peu d'erreurs quand ce sont des entiers stockés en float ou double

    Bien sûr, il ne faut jamais procéder de la sorte mais cela montre qu'on peut le faire.

    Il faut noter que curieusement C n'implémente pas le swap comme un opérateur de couples, alors que la plupart des assembleurs le font en une instruction.

  5. A voir en vidéo sur Futura
  6. #5
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Merci pour la confirmation!

  7. #6
    Tryss

    Re : échange nombre, sans variable intermédiaire.

    Il y a une méthode plus élégante, qui utilise les opérateurs binaires et qui permet donc d'échanger exactement le contenu de deux variables :

    Code:
    A = A xor B
    B = A xor B
    A = A xor B
    Si on prend A = 00110101 et B = 11011001, alors la série d'instruction devient :

    A = 00110101 xor 11011001 = 11101100
    B = 11101100 xor 11011001 = 00110101 (on a récupéré le A originel)
    A = 11101100 xor 00110101 = 11011001 (on a récupéré le B originel)


    Et si on veut jouer au guru obfuscateur du C, /!\ A ne pas faire, ni en cours ni en situation de programmation réelle /!\, ça peut s'écrire (c'est rigolo) :

    Code:
    a^=b^=a^=b;

    Maintenant, en conditions réelles, il vaut mieux, sauf très très rares exceptions, utiliser une variable intermédiaire
    Dernière modification par Tryss ; 14/09/2013 à 20h41.

  8. #7
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Ah il me semblait bien qu'il y avait moyen de faire avec du XOR, helas ça ne marche pas sur du float... http://codepad.org/y9wSWyJu Peut-être avec un cast? Ou alors du inline-ASM?

  9. #8
    Tryss

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par grosmatou75001 Voir le message
    Ah il me semblait bien qu'il y avait moyen de faire avec du XOR, helas ça ne marche pas sur du float... http://codepad.org/y9wSWyJu Peut-être avec un cast? Ou alors du inline-ASM?
    Erf, il me semblait que ça marchait, mais effectivement, les bitwise opérateurs sur les flottants, ça ne se fait pas. Je ne me rappellai plus de cette particularité (qui fait sens, puisque la représentation des flottants n'est pas spécifiée dans la norme du C et dépend du hardware)

  10. #9
    Olympe02

    Re : échange nombre, sans variable intermédiaire.

    J'ai essayé ceci :

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
        int a, b; // déclarer les variables
        cout << "Saisir deux nombres" << endl; // afficher les variables
        cin >> a >> b; // saisir les nombres
        a = a + b;
        a = a - b;
        a = a - b;
        cout << a << b;
    
    
        return 0;
    }

  11. #10
    Jack
    Modérateur

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par Olympe02 Voir le message
    J'ai essayé ceci :

    Code:
        a = a + b;
        a = a - b;
        a = a - b;
    }
    C'est bien d'avoir essayé, mais tu ne donnes pas le résultat.

    Je doute que ça réponde à ton problème puisque les 2 premières lignes ci-dessus mêment à a = a, sans que b n'ait changé. ca ne sert donc à rien. Du coup la 3ème ligne n'apporte rien non plus.

    A+

  12. #11
    bisou10

    Re : échange nombre, sans variable intermédiaire.

    C'est bien, tu as essayé, mais ca ne marche pas

  13. #12
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Bonsoir,

    je ne crois pas que ca fonctionne Olympe. Testez le programme résultant, c'est la seule façon de vous en convaincre avant de rendre le résultat.

    On peut aussi écrire le swap en une ligne mais 2 assignations et 2 opérations au lieu de 3 et 3
    a = (a+b)-( (b = a) );

    Mais j'y pense seulement maintenant : attention à l'overflow. Il ne faut pas que la somme dépasse INT_MAX ( valeur prédéfinie par le compilateur )
    Vous ne pouvez pas écrire if( a + b > INT_MAX ) bien sûr , mais pour ruser il faut avoir une idée des signes de a et b ou bien tester et c'est un peu lourd à écrire ( quoique facile ).

    Vu qu'on vous a aidé , il doit vous rester du temps pour le faire
    Essayez de trouver quelque chose autour de cette forme de test :
    if( a > INT_MAX -b ) // a et b positifs

  14. #13
    Olympe02

    bloque dans un calcul en C++

    edit supprimé

  15. #14
    polo974

    Re : échange nombre, sans variable intermédiaire.

    coucou, j'ai joué avec des cast de pointeur pour échanger des floats.
    ça marche (mais attention à la taille du float et à celle du int...)

    alors, je me suis dit, faisons du obfuscated et là, j'ai un affreux problème...

    Code:
        A^=B;
        B^=A;
        A^=B;  // fonctionne
    
        A^=B^=A^=B;  // ne fonctionne pas...
    
        A^=B,B^=A,A^=B;  // fonctionne
    en fait, dès que A et B sont des éléments de tableau avec ou sans parenthèse autour, de la forme *a ou a[0], bref ai-je dépassé mon niveau d'incompétence ou juste trouvé un bug dans gcc ? ? ?
    (par contre si A et B sont de bêtes int, sans tableau, ça passe)

    ci joint le code douteux:
     Cliquez pour afficher

    en blindant ou non de parenthèses le #define, on a le même résultat...
    en utilisant une union au lieu des cast et pointeurs on a aussi le même résultat...
    Jusqu'ici tout va bien...

  16. #15
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Salut,

    un cast est une assignation par une variable intermédiaire et non une façon différente de traiter une variable abstraite ( dommage ! ).
    En reposant le pseudo code avec une assignation/opération à la ligne, vous devriez retomber sur la même chose

  17. #16
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    un cast est une assignation par une variable intermédiaire et non une façon différente de traiter une variable abstraite ( dommage ! ).
    Tu peux préciser? Je ne comprends pas très bien cette histoire de variable intermédaire...

    edit:

    a=13.5;
    b=42.6;
    Voila ce qui est curieux, les mêmes valeurs que j'avais utilisé pour mes bricolages! Tu n'aurais pas trouvé un début de code sur codepad par hasard?
    Dernière modification par grosmatou75001 ; 15/09/2013 à 19h27.

  18. #17
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par grosmatou75001 Voir le message
    Tu peux préciser? Je ne comprends pas très bien cette histoire de variable intermédaire...
    double dd = 4.0 ,xx = 9.0 ;
    int a = 5 ;

    xx += ( (double ) a + dd ) ;
    <==>
    double aa = (double) a ; // aa temporaire
    xx += (aa + dd) ;

  19. #18
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Merci, j'ai appris un truc.

  20. #19
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par grosmatou75001 Voir le message
    Voila ce qui est curieux, les mêmes valeurs que j'avais utilisé pour mes bricolages! Tu n'aurais pas trouvé un début de code sur codepad par hasard?
    Je retire ma question, j'avais oublié que j'avais posté moi-même le lien vers codepad (#7). Parfois je me demande...

  21. #20
    polo974

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par grosmatou75001 Voir le message
    ...

    Voila ce qui est curieux, les mêmes valeurs que j'avais utilisé pour mes bricolages! Tu n'aurais pas trouvé un début de code sur codepad par hasard?
    ben si, il était là pour ça, non ? ? ?

    Citation Envoyé par mike.p Voir le message
    double dd = 4.0 ,xx = 9.0 ;
    int a = 5 ;

    xx += ( (double ) a + dd ) ;
    <==>
    double aa = (double) a ; // aa temporaire
    xx += (aa + dd) ;
    Sauf que moi j'ai casté les pointeurs, ce n'est donc pas du tout la même chose...
    j'utilise le même contenu de la mémoire d'une façon différente (ce qu'on peut aussi faire avec une union).
    mais dans les 2 cas, ça pose problème dans l'écriture sur une ligne.
    Dernière modification par polo974 ; 16/09/2013 à 05h09.
    Jusqu'ici tout va bien...

  22. #21
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Salut,

    On ne caste pas un pointeur dans une assignation de ce type. Relisez votre proposition de code

    A bientôt

  23. #22
    bisou10

    Re : échange nombre, sans variable intermédiaire.

    Bonjour,

    Je ne rentre pas dans vos points de détails, ma pratique du C bien que professionnelle est au mieux irrégulière

    Par contre tel que je comprends son énoncé, et au vue de son niveau, je dirais que ce que la solution attendue tourne autour de l'utilisation d'un pointeur, tout en gardant 2 variables locales a et b. C'est effectivement faux au niveau allocation de ressources, ou alors il faut laisser travailler longtemps les optimisations du compilo.

    Bonne journée !

  24. #23
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Bonjour,

    oui c'est ça et surtout à gauche dans les assignations. Il ne faut pas oublier que C ne protège pas les variables.

    // Si double fait 128 bits et int 64
    double dd = atan(1) ;
    int a ;
    ( double ) a = dd ; // fera des dégats sur les 64 bits suivants

    Or c'est bien ce que font les #define de l'exemple, C doit caster à gauche à chaque assignation.

    Avant que les compilateurs ne surveillent le cast , on passait beaucoup de temps à éliminer les erreurs de format. Aujourd'hui, le sport, c'est de compiler avec un niveau de warning maximum et de n'en obtenir aucun. Le programme peut être stupide mais il a 1000 fois moins de problèmes de mémoire.

    Ceci dit, je ne comprends pas que l'initiation passe par C. Javascript est devenu un outil complet , facile et parfois incontournable. On pourra ensuite, avec très peu d'efforts aller à C , quand le besoin se présentera.

  25. #24
    grosmatou75001

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par polo974 Voir le message
    ben si, il était là pour ça, non ? ? ?
    Oui oui bien sûr, j'avais oublié que je l'avais posté, pardon.

  26. #25
    polo974

    Re : échange nombre, sans variable intermédiaire.

    Citation Envoyé par mike.p Voir le message
    Salut,

    On ne caste pas un pointeur dans une assignation de ce type.
    Affirmation péremptoire s'il en est...
    Relisez votre proposition de code

    A bientôt
    Et... ? ? ?
    (il est très bien mon code)
    En C, j'ai le droit de caster comme je l'ai fait, et ça marche normalement très bien.
    C'est extrêmement utile pour réaliser des bidouilles sur des float dont on maîtrise le format.

    bref, ça marche tant que je ne fais pas d'affectations multiples, sans virgule sur la même ligne.

    Mais le pb se retrouve aussi sur les unions, donc c'est à mon avis plus un problème de sur-optimisation qui engendre le pb.
    et même en blindant de parenthèses genre:
    Code:
    A^=(B^=(A^=B));
    donc en ne laissant aucun doute sur les préséances lors des affectations, ça coince...

    (A et B sont définis par #define , par exemple a et b pour de simple int, (*a) et (*b) pour les premiers éléments de tableau d'int, ...):

    Code:
    A^=B^=A^=B;
    marche avec des types simples mais merdoie avec soit des union, soit des éléments de tableau, soit des cast de pointeur "de la mort qui tue".
    alors que les écritures:
    Code:
    A^=B;
    B^=A;
    A^=B;
    ou
    Code:
    A^=B,B^=A,A^=B;
    et les mêmes #define ne posent pas problème.

    (précision, dans tous les cas, mon float et mon int ont un même sizeof de 4, aucun pb de ce coté...)

    après essais, ça pose aussi pb avec:
    Code:
    A=A^(B=B^(A=A^B));
    Jusqu'ici tout va bien...

  27. #26
    mike.p

    Re : échange nombre, sans variable intermédiaire.

    Vous donnez vous même la réponse : float et int sont en 32 bits. Donc les valeurs sont simplement fausses. Cependant, certains compilateurs ajoutent eux mêmes des cast sur les opérations non castées ( ils acceptent ainsi double dd = 1 ; ). Ca peut influer.

    Attention à ne pas assumer des règles dont ne tient pas compte le compilateur et encore moins l'optimiseur.

    Cast est aux risques et périls de son utilisateur. Le type va définir l'encombrement de la destination qui sera entièrement occupée au moment d'une assignation.

    Au revoir.

  28. #27
    polo974

    Re : échange nombre, sans variable intermédiaire.

    Encore une fois, je ne fais AUCUN cast de float en int ou vice/versa, je fais des cast de pointeurs.
    Il n'y a aucun cast implicite.

    Un pointeur (sur les machines usuelles que nous utilisons tous les jours et depuis que le modèle segmenté Intel n'est plus qu'un mauvais souvenir pour quelques anciens) se fiche de savoir ce qu'il y a dedans, seule la taille du type pointé est géré (et comme ici, c'est la même...)...

    Donc les opérations se font, mais quelque part, le compilo se mélange les pinceaux quand on utilise autre chose que des types simples.

    et comme dit précédemment:
    avec
    Code:
    int a[10],b[10];    // var globales pour faciliter lecture assembleur
    ...
        a[0]=-85;
        b[0]=85;
    Code:
        a[0]^=b[0]; 
        b[0]^=a[0]; 
        a[0]^=b[0];
    et
    Code:
        a[0]^=b[0],b[0]^=a[0],a[0]^=b[0];
    ok
    Code:
        a[0]^=b[0]^=a[0]^=b[0];
    pas ok... et là, pas de cast de pointeurs, pas d'union, juste l'usage de variable dans un tableau...

    alors que si j'utilise de simples int, tout va bien...
    ....

    bon, j'ai compilé les différents cas (int et tableau d'int en variables globales pour simplifier) avec l'option -S et j'ai comparé les codes assembleurs générés.
    La conclusion est qu'il y a un définitivement bug dans gcc.

    et puisque l'optimiseur a été mis sur la table, j'ai compilé et testé avec les options simples disponibles: et là, surprise, le bug disparaît dès qu'on n'est plus en -O0 (valeur par défaut) ! ! !

    Bref, la conclusion momentanée est de ne plus compiler sans optimiser un poil...
    Jusqu'ici tout va bien...

  29. #28
    polo974

    Re : échange nombre, sans variable intermédiaire.

    Tout étant parti de là:
    Citation Envoyé par Tryss Voir le message
    ...
    Et si on veut jouer au guru obfuscateur du C, /!\ A ne pas faire, ni en cours ni en situation de programmation réelle /!\, ça peut s'écrire (c'est rigolo) :
    Code:
    a^=b^=a^=b;
    Maintenant, en conditions réelles, il vaut mieux, sauf très très rares exceptions, utiliser une variable intermédiaire
    Citation Envoyé par polo974 Voir le message
    ...
    La conclusion est qu'il y a un définitivement bug dans gcc.
    ...
    Finalement, le définitif n'est que momentané...
    Après avoir allumé tous les warning ou presque (options -pedantic -std=gnu99 -Wall), il apparaît un message:
    warning: operation on 'a' may be undefined [-Wsequence-point]

    Car il y a certaine chose qui ne sont pas définies en C, et les affectations de la même variable sur la même ligne peuvent en faire partie...

    Bon, c'est quoi ça les "sequence-point" (un peu de gogol, un peu de lecture et hop, je mourrais encore un peu moins bête, je vous laisse fouiller)...

    Bref:
    Code:
    a^=b^=a^=b;
    n'est pas déterminé...
    pour garder la logique obfuscatrice et avoir un résultat déterminé, il faut donc l'écrire comme cela:
    Code:
    a^=(b^=(a^=b,a),b);
    mais même écrit en trois lignes, l'optimiseur fonctionne aussi bien...
    Dernière modification par polo974 ; 17/09/2013 à 14h49. Motif: erreur balise
    Jusqu'ici tout va bien...

  30. #29
    bokan

    Re : échange nombre, sans variable intermédiaire.

    Franchement, c'est un exercice débile !

    Autant la solution avec les xor est élégante et intéressante pour un programmeur chevronné, autant demander à des élèves de faire quelque chose qu'il ne faut surtout pas faire en vrai me semble débile.

    Il y a tellement d'autres exercices simples à proposer pour maîtriser la programmation, pourquoi faire perdre du temps et décourager les élèves avec des exercices comme ça ?

    Des profs qui manquent autant de pédagogie, ça m'énerve ! Fallait que je le dise !

  31. #30
    polo974

    Re : échange nombre, sans variable intermédiaire.

    Et pourquoi ne faut-il surtout pas le faire en vrai?

    Et pourquoi ne pas faire découvrir qu'il existe des opérations sans perte d'info comme le xor (ou l'addition s'il n'y a pas de retenue) et d'autre avec, comme le and ou le or?
    Jusqu'ici tout va bien...

Discussions similaires

  1. Réponses: 82
    Dernier message: 12/09/2013, 23h57
  2. Quelle est la formule pour calculer le nombre de combinaisons, avec taille variable et sans ordre ?
    Par initial32 dans le forum Mathématiques du collège et du lycée
    Réponses: 6
    Dernier message: 09/09/2013, 12h35
  3. [Matlab] Nombre de paramètres variable
    Par wolring dans le forum Logiciel - Software - Open Source
    Réponses: 1
    Dernier message: 11/08/2010, 04h53
  4. Somme d'une suite avec un nombre de termes variable
    Par inviteaa60f5ee dans le forum Mathématiques du supérieur
    Réponses: 2
    Dernier message: 11/09/2006, 12h57