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 :

Optimiser son code


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut Optimiser son code
    Bonjour à tous !

    Je souhaiterais optimiser un code source (niveau vitesse d'exécution), mais je ne sais pas du tout comment m'y prendre. Les quelques techniques que j'ai trouvées sur Internet n'ont rien données... Ce code permet de trouver les briques d'Euler (voir http://fr.wikipedia.org/wiki/Brique_d'Euler)

    Mon code source hébergé :
    http://code.empreintesduweb.com/6346.html

    J'utilise la bibliothèque GMP afin de pouvoir gérer de très grands nombres.

    Voici ce que fait mon programme :
    1. Il déclare trois variables GMP correspondant aux arrêtes du parallélépipède;
    2. Il les incrémente grâce à des boucles imbriquées afin de tester toutes les triplettes de nombres possibles (1 - 1 - 1 ; 1 - 1 - 2 ; 1 - 1 - 3...)
    3. Il teste pour chaque triplette si elle convient, grâce à la fonction CalculerEtTesterDiagonaleFace.


    Ici, j'ai mis un maximum de 1000 pour chaque boucle, mais j'aimerais aller plus loin, et c'est pour cela que j'aimerais optimiser mon code.
    Pouvez-vous m'aider ?
    Merci !
    Syrll

  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
    C'est un problème d'algorithmie.
    La base de l'optimisation, c'est de s'arranger pour ne pas calculer.

    Moins tu calculeras de chose, mieux ce sera.
    Tu as une grille cubique de taille N*N*N

    à présent, wikipedia lui meme dit que tu n'en trouvera pas.

    Abandonne l'optimisation, meme avec des gros calculateurs, les chercheurs ont montré qu'il n'y en a pas dont les cotés sont inférieurs à mille milliards.

    Ton pc ne suffira pas.

    Par contre, si tu es un chercheur, le problème est autre, et je pense que si tu nous demandes notre avis, tu n'es pas près d'en trouver une.

    En fait, c'est pour la brique parfaite d'euler.

    Cela dit, tu peux te baser sur les maths, pour ne chercher que des candidats.

    Par exemple, tu sais déjà que tous les cotés 1 sont inutiles, car sqrt(1 + n²) n'est jamais un entier.
    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
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Non, justement, pas la brique parfaite d'Euler, juste les premières briques...

    Après, pour optimiser l'algorithme, j'ai déjà cherché, mais n'ai rien trouvé...
    J'ai par exemple supposé qu'il n'y avait qu'un B pour lequel sqrt(A² + B²) est entier si A est défini (ce qui m'aurait grandement facilité la tâche), mais un contre exemple m'a prouvé le contraire : A = 9 et B = 12 ou 40, les deux fonctionnent... Mais, mis à part ça, n'y a-t-il pas un moyen de booster un programme ?

    Syrll

  4. #4
    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
    Avec quel compilateur compiles-tu et quelles options lui passes-tu ?

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Je compile avec GNU GCC Compiler, et les options sont -g, -Wall, -Wextra et -O2 (pour la rapidité)

  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
    Tu pourrais tenter de passer en O3 déjà. Il y a une page dédiée aux options d'optimisation de gcc : http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

    Je regarde ton code et je vois aussi que dans ta fonction, tu fais init puis clear. Dans la boucle, ça veut dire que tu refais ça a chaque itération. Je ne connais pas cette bibliothèque mais regarde si tu ne peux pas avoir des variables avec une portée plus grande et d'avoir une fonction plus légère pour réinitiliaser ces variables. Clairement, tu appelles tout le temps ta fonction de test des diagonales, il faut trouver la meilleure version de cette fonction.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Code version 2 :
    http://code.empreintesduweb.com/6359.html
    Je suis également passé en -O3

  8. #8
    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
    Bonjour,

    Déjà, est ce que tu peux m’expliquer à quoi ça rime ton fichier position.txt ?
    Parce que ça rend le code moins lisible, et c’est clairement pas bon pour les perf’ car à cause de ça, dans ton inner loop tu fais (en plus du calcul) :
    - des I/O sur disque genre rewind
    - du parsing de string (via mpz_set_str)
    - des if/else pour assigner une variable
    Et ça, ça tue les perf’

    Si je retire tout ce qui est lié à la gestion du fichier, ton code se prend x6 niveau vitesse chez moi.
    Ici j’ai lancé avec MAX à 2 000.
    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
    % time ./ref                           
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./ref  3,12s user 3,96s system 99% cpu 7,087 total
     
    % time ./ref                           
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./ref  2,99s user 3,58s system 99% cpu 6,569 total
     
    % time ./ref                           
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./ref  2,96s user 3,65s system 99% cpu 6,610 total
     
    % time ./euler                         
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./euler  1,10s user 0,00s system 99% cpu 1,103 total
     
    % time ./euler
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./euler  1,06s user 0,00s system 99% cpu 1,059 total
     
    % time ./euler
    44 - 117 - 240 n85 - 132 - 720 n88 - 234 - 480 n132 - 351 - 720 n140 - 480 - 693 n160 - 231 - 792 n170 - 264 - 1440 n176 - 468 - 960 n187 - 1020 - 1584 n220 - 585 - 1200 n240 - 252 - 275 n264 - 702 - 1440 n280 - 960 - 1386 n308 - 819 - 1680 n320 - 462 - 1584 n352 - 936 - 1920 n480 - 504 - 550 n720 - 756 - 825 n960 - 1008 - 1100 n1008 - 1100 - 1155 n1200 - 1260 - 1375 n1440 - 1512 - 1650 n1680 - 1764 - 1925 n
    ./euler  1,08s user 0,00s system 99% cpu 1,078 total
    (on remarque que là où je gagne le plus c’est sur tout ce qui est appels systèmes donc principalement I/O ici).
    ref étant ton code original, euler étant ton code sans la gestion du fichier, c’est-à-dire ça :
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    #include <gmp.h>
     
    int CalculerEtTesterDiagonaleFace(mpz_t nb1, mpz_t nb2);
     
    int main(void)
    {
        mpz_t A;
        mpz_t B;
        mpz_t C;
        const unsigned long long MAX = 2000;
     
        mpz_init(A);
        mpz_init(B);
        mpz_init(C);
        mpz_set_si(A, 2);
     
        while(mpz_cmp_ui(A, MAX) < 0) {
            mpz_set(B, A);
            while(mpz_cmp_ui(B, MAX) < 0) {
                // Si ?(A² + B²) est un entier, autrement dit si la diagonale est un entier
                if(CalculerEtTesterDiagonaleFace(A, B)) {
                    mpz_set(C, B);
                    while(mpz_cmp_ui(C, MAX) < 0) {
                        if(CalculerEtTesterDiagonaleFace(B, C ) &&
                           CalculerEtTesterDiagonaleFace(C, A)) {
                            gmp_printf("%Zd - %Zd - %Zd n", A, B, C);
                        }
                        mpz_add_ui(C, C, 1);
                    }
                }
                mpz_add_ui(B, B, 1);
            }
            mpz_add_ui(A, A, 1);
        }
        return 0;
    }
     
    int CalculerEtTesterDiagonaleFace(mpz_t nb1, mpz_t nb2)
    {
        mpz_t puiss1;
        mpz_t puiss2;
        mpz_t res;
     
        mpz_init(puiss1);
        mpz_init(puiss2);
        mpz_init(res);
     
        mpz_pow_ui(puiss1, nb1, 2);
        mpz_pow_ui(puiss2, nb2, 2);
     
        mpz_add(res, puiss1, puiss2);
     
        int booleen = mpz_perfect_square_p(res);
     
        mpz_clear(puiss1);
        mpz_clear(puiss2);
        mpz_clear(res);
     
        return booleen;
    }

    Sinon, niveau option de compilation j’ai utilisé les même pour les deux codes donc je ne pense pas que ça joue mais pour info’ j’ai utilisé ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    % alias gcc_release
    gcc -std=c99 -Wall -Wextra -pedantic -Wdouble-promotion -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wfloat-equal -Wundef -Wshadow -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wjump-misses-init -Wlogical-op -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wredundant-decls -Wnested-externs -pipe -fstrict-aliasing -O3 -flto -march=native -DNDEBUG
    Ce qui est vraiment utile ici niveau perf’ c’est -O3 -march=native -DNDEBUG (la LTO ne sert à rien dans le cas présent et les autres options c’est pour avoir des warnings).

    Édit : je fais référence à ta V1 (la V2 ayant été publiée pendant la rédaction de mon post je ne l’ai pas encore regardé).

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Le fichier est fait pour enregistrer la position de la boucle (le nombre de tours effectués) afin de reprendre au même endroit, même après avoir arrêté le programme.

  10. #10
    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 syrll Voir le message
    Le fichier est fait pour enregistrer la position de la boucle (le nombre de tours effectués) afin de reprendre au même endroit, même après avoir arrêté le programme.
    Et tu en as vraiment besoin ?

    Si oui, il va falloir faire autrement.
    Du genre, tu lis le fichier une fois au démarrage pour faire ton initialisation.
    Et quand le programme s’arrête, tu sauvegardes le dernier point calculé (genre si tu es sur Linux tu met un signal handler sur SIGINT (le signal envoyé par Ctrl+C) qui va faire la sauvegarde avant de quitter le programme).
    Comme ça ta boucle de calcul ne fait que du calcul.

    Et je plussoie aussi la remarque de Bktero : les mpz_init/mpz_clear (qui font des malloc/free) dans une boucle serrée, ça tue les perfs (c’est normal, une allocation mémoire ce n’est pas gratuit). J’ai un boost de vitesse x3 si je les initialise une fois au début, je les libère à la fin et je me contente d’une mise à 0 au début de la fonction CalculerEtTesterDiagonaleFace.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    C'est bon, j'ai réussi ! En faisant en sorte de ne pas calculer les puissances répétitivement, le temps d'exécution est descendu à... 0,130 secondes !
    Quelques autres petites modif's, à voir ici
    Merci !!
    Syrl

  12. #12
    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
    Je pense qu’il y a même moyen de gagner encore de manière non négligeable en mémoïsant CalculerEtTesterDiagonaleFace et en multithreadant le code.
    (Je pourrais donner plus de détails mais probablement pas avant ce week-end car je vais être pas mal occupé les deux jours à venir :/)

  13. #13
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Bonjour,

    j'arrive un peu tard mais je me permets de rajouter juste quelques remarques :

    • La première optimisation se fait sur l'algorithme
      En cela je rejoins leternel. Sur la page anglaise de wikipedia Perfect cuboid, on trouve une caractérisation des briques primitives avec des critères de divisibilités (tests certainement plus efficaces qu'un test de carré parfait). Entre autre on nous dit que (mais faut-il croire wikipédia ?) :
      • une des arrêtes doit-être divisible par 16, une autre par 4 et la dernière doit être impaire.
      • deux des arrêtes doivent être divisibles par 3 dont une aussi par 9
      • une des arrêtes doit être divisible par 5
      • une des arrêtes doit être divisible par 7
      • une des arrêtes doit être divisible par 11
      • une des arrêtes doit être divisible par 19

      Le test du carré parfait ne sera ensuite effectué que sur les triplets passant tous les tests de divisibilité.
      C'est peut-être une piste à étudier ....

      Une fois que tu as une liste conséquente de briques primitives, tu pourras créer les briques non primitives (si tu en as besoin).

    • Éviter dans le source ce qui est coûteux
      Les accès disque, les accès mémoire épars, ... Cela a déjà été évoqué

    • Utiliser une version optimisée des bibliothèques externes
      La doc de GMP t'indique succinctement comment procéder ...

    • Utiliser les options d'optimisations de ton compilateur
      dèjà évoqué

    • Utiliser un profiler
      gprof, cachegrind, ....

    • Si le programme le permet : paralléliser
      threads, gomp, .... déjà évoqué


  14. #14
    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
    Tu peux même ruser, en considérant qu'une brique parfaite est composé de 3 paires de rectangles parfaits.

    Génère une liste de tels rectangles (solutions entières de a²+b²=c²), puis quand tu estimes en avoir assez, fait de la combinatoire sur ces rectangles.

    Ta liste ne devrait comprendre que des triplets ordonnés (a<b<c)
    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

  15. #15
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut Optimisation
    Bonjour la réponse de @leternel , revient à peu près à ce que j'ai répondu sur un autre forum bonne continuation à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

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

Discussions similaires

  1. comment optimiser son code?
    Par airod dans le forum Débuter
    Réponses: 1
    Dernier message: 28/07/2009, 17h38
  2. optimiser son code
    Par giuseppe2 dans le forum VB.NET
    Réponses: 2
    Dernier message: 08/09/2008, 15h36
  3. comment optimiser son code en calcul ???
    Par gronaze dans le forum C
    Réponses: 5
    Dernier message: 21/03/2006, 10h41
  4. Réponses: 9
    Dernier message: 22/02/2006, 11h32
  5. [Perf] Comment optimiser son code ?
    Par Frifron dans le forum Général Java
    Réponses: 12
    Dernier message: 11/08/2005, 09h05

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