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

Algorithmes et structures de données Discussion :

Convertir un nombre en base 26


Sujet :

Algorithmes et structures de données

  1. #21
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Magie
    Bonsoir,

    Croire que compilateur et cpu sont suffisamment intelligents pour que le développeur ne soit qu'un consommateur aveugle de ressources informatiques est un leurre moderne.

    Reprenons l'exemple de la division par 2. Elle sera bien sûr remplacée, par quelque chose comme sar rax, 1. Donc pourquoi s'en faire ? Mais un n div a avec a une variable (pas une constante) qui serait de la forme 2^u calculé à l'exécution ne sera pas transformé en sar rax, u à la compilation.

    Par ailleurs, les CPU modernes possèdent des instructions qui ne sont plus du tout basiques. Comme elles correspondent à un code complexe en langage évolué, le compilateur ne saura pas en optimiser la traduction en les utilisant. Par exemple, si on écrit une fonction qui compte les bits à 1 d'un entier, ce qui demande quelques lignes de code, le compilateur ne traduira pas tout ce code en un simple popcnt rax. Bien sûr, une bibliothèque offrira un popcount(int i), mais elle sera écrite en assembleur.

    Il est certes inutile de faire une simple traduction en assembleur d'un code en langage élevé. Le compilateur fait ça bien mieux que nous. Mais l'assembleur offre souvent des potentialités de solutions qui ne sont pas des traductions.

    Je ne recommande nullement d'utiliser l'assembleur partout mais de se poser la question à chaque fois que le temps devient critique (à supposer que le choix algorithmique est bon). Il n'y a pas non plus concurrence entre les techniques automatiques et manuelles mais collaboration : par exemple l'entre-laçage de code assembleur aide le cpu à optimiser micro-parallélisme et out of order (et rendre certes le code un peu plus illisible).

    Quelquefois le gain est minime (quelques 10e de %) mais souvent il multiplie par plus de 2 (voire sensiblement plus) les performances.

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  2. #22
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Evolution ou révolution ?
    Bonsoir CoderInTheDark,
    Citation Envoyé par CoderInTheDark Voir le message
    ...On nous disait que la multiplication et la division coûtaient cher alors à la place de mul 2, d0; on faisait add d0, do;...
    Eh bien c'est toujours vrai. Et la division coûte bien plus cher que la multiplication qui coûte elle-même plus cher que les décalages, lesquels sont bien moins efficaces que les additions, soustractions, and, or ...

    Ce qui a changé est l'aptitude des compilateurs à choisir mieux les instructions mais ce n'est pas encore parfait.

    Salut.
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  3. #23
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Citation Envoyé par Guesset Voir le message
    Bonsoir,

    Croire que compilateur et cpu sont suffisamment intelligents pour que le développeur ne soit qu'un consommateur aveugle de ressources informatiques est un leurre moderne.

    [...]
    Ce que je dis est : «un compilateur, lorsqu'on lui demande, optimisera mieux le code que la très grande majorité des codeurs», et je ne pense pas m'avancer en disant 99.99% des codeurs.
    Cela signifie souvent que ce qu'un codeur (maladroit) pense être une optimisation n'en sera pas une.
    Optimiser un code c'est avant tout utiliser un profiler pour savoir où optimiser est utile, puis laisser le compilo optimiser la partie hot du code détectée en lui réintroduisant les données collectées par le profiler.
    Ce n'est pas être aveugle que d'utiliser les outils modernes un peu plus évolués que ceux dont on disposait dans les années 80.

  4. #24
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 057
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 057
    Points : 9 397
    Points
    9 397
    Par défaut
    Il y a 2 choses qui ont changé en 30 ans : les compilateurs, et (surtout) le profil des développeurs.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  5. #25
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    1 066
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 066
    Points : 2 569
    Points
    2 569
    Par défaut
    Ca y est ça dérape et devient hors sujet.

    Bon je vous laisse vous penserez à éteindre la lumière quand vous aurez terminé
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

  6. #26
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut
    Bonjour, je viens en retard. Bien que marqué résolu, il y a ce détail qui me chagrine.
    Citation Envoyé par CoderInTheDark Voir le message
    ...
    Je peux me limiter à YZ, car je ne veux pas gérer ce cas pour éviter une conditions en plus dans ma boucle while.
    ..
    Cette obligation de limitation à une grandeur bien que satisfaisant le besoin. Si un jour ce besoin évoluait pour juste une colonne supplémentaire au dessus de cette limite ...
    C'est quand même étonnant vu que la chose ne semble pas vraiment différent de la traduction des champs de données d'une base ... même si les symboles representatifs sont les 26 lettres de l'alphabet. Il y a un truc qui m'échappe dans tout ce que j'ai lu.
    Il faudrait que je tente quelque chose là dessus.
    pour comprendre pourquoi.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  7. #27
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut
    Bonjour,
    une journée enfin qui change des routines ennuyantes !
    Alors , j'ai naïvement abordé le problème en pensant aux expériences classiques de conversion de valeurs textuelles hexa etc.

    D'abord pour m'inspirer un code vite fait de conversion hexadecimale, qui s'apparente trait pour trait au problème, sauf a 1 detail près, qui va me sauter a la figure.

    je balance tout le brouillon du code avec les commentaires.

    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
    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    void convHexDec()
    {
        // 0-9 \48-57, a \97-122, A \65-90
        char *hexref = "0123456789ABCDEF";
        char hexnum [17] = {'F', '1', '0', 'E'}, *hx ;
        long nb = 0, b = 16, n = 1, i = len(hexnum) ;
        hx = hexnum + i - 1;
        nb = *hx - (*hx > 47 && *hx < 58 ? 48 : 55) ;
     
        // conversion de la chaine stockee dans hexnum
        while ( --i && hx-- )
        {
            n*= b ;
            nb += n * ( *hx - (*hx > 47 && *hx < 58 ? 48 : 55) ) ;
        }
        printf("\nhex_dec(%s) == %0lX = %ld\n", hexnum, nb, nb) ;
     
        // conversion inverse du nombre
        n = nb ;
        while (n)
        {
            *hx++ = hexref[n % b] ;
            n/= b;
        }
        printf("dec_hex(%ld) == %s\n", nb, hexnum) ;
        // la chaine constituee dans le sens inverse, devra etre lu en consequence
        // si on doit eviter cela, a la conversion il faut pouvoir evaluer
        // l'indice de la puissance avec quelque chose comme : i = log(nb) / log(b) ; while ( i ) hexref[i--] ...
        // je verrais cela en dernier lieu, passons au cas qui interpelle.
     
    }
     
    // le probleme d'etiquetage d'indices de colonne
    void convb26()
    {
        char *ltref ="ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
        char lret [6] = { 'Z', 'X', 'A', 'Y' }, *r =lret ;
        int b = 26, s = 64 ;
        long i = 0, n = 1, nb = 0;
     
        // j'ai naivement alors adapte le code de traduction hexa en negligeant un detail majeur et patatra !
        // j'ai pris un peu de temps de tatonnements avant de comprendre le truc,
        // voyant que rien ne change dans le principe, sauf un detail, qui
        // etait l'ordre de numerotation de champ debutant a 1 au lieu de 0.
        // nous ramenant a un probleme de numerotation d'ordre de champ commencant a 1 simplement.
        // Pour la comprehension, la formule literale est ceci :
        // puissance indice etape * valeur converti du champ + valeur etape precedent .
        // La numerotation des champs commencant a 1, on fait +1 a la volee en fixant a 64 la soustraction.
        // on aura alors dans la traduction de la base champ + 1, j'avoue que c'est quand meme deroutant.
     
        i = strlen(lret) ;
        r+= i - 1;
        nb+= n * (*r - s) ;
        while( --i && r-- )
        {
            n *= b ;
            nb+= n * (*r - s) ;
        }
        printf("\ncol(%s) == %ld\n", lret, nb) ;
     
        // A la conversion inverse, j'ai eu la meme desagreable surprise avant de rectifier, 
        // me rappellant qu'il y avait un +1 pour chaque champ lors du calcul du nombre a deduire.
        n = nb ;
        while (n--)
        {
            *r++ = ltref[n % b] ;
            n/= b ;
        }
        printf("col(%ld) == %s\n", nb, lret) ;
     
        // pour eviter l'affichage inverse, une formule de calcul d'indice max.
    //    i = log(nb) / log(b) ; n = pow(b, i) ;
    //    i += ( (i == 1) * (nb > b) ) || ((i < 4) * (nb - n - b) >= b ) ; // zut! autant faire une  boucle rapide
    //    for(n = nb; n--; n/=b, i++) ;
    //    for (n = nb; i-- ; n/= b)
    //        lret[i] = ltref[--n % b] ;
    //    printf("\ncol(%ld) == %s\n", nb, lret) ;
        // J'ai rate la formule de calcul d'indice, pour choisir une boucle.
        // j'ai vraiment pas vu la bonne formule avec des grandeurs de puissance differentes.
        // si quelqu'un trouvait une estimation d'indice plus cool et le faisait savoir.
     
        // opter pour realiser l'inversion a la suite directement est l'approche raisonnable,
        // si le programme utilisant la chaine n'est pas prepare pour une lecture inversse
        n = nb, i = 0 ;
        while (n--)
        {
            lret[i++] = ltref[n % b] ;
            n/= b ;
        }
        // rotation de la chaine
        for (i/= 2, r--; i-- ;) {
            BIT_SWAP(lret[i], r[-i]);
        }
        printf("col(%ld) == %s\n", nb, lret) ;
     
    }
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  8. #28
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Pas nul ?
    Bonjour NVCfrm,
    Citation Envoyé par NVCfrm Voir le message
    ...il y a ce détail qui me chagrine. Cette obligation de limitation à une grandeur bien que satisfaisant le besoin. Si un jour ce besoin évoluait pour juste une colonne supplémentaire au dessus de cette limite ...
    Comme toi cela me gênait. C'est pourquoi j'ai proposé un deuxième algorithme plus général qui ne fonctionne pas correctement.

    En fait, il s'avère que c'est bien un codage par position mais sans 0 avec des chiffres an qui vont de 1 à 26 : a3.23 + a2.262 + a1.261 + a0.260. On voit tout de suite le lien avec ABCD...
    Alors la conversion devient simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char str[16}; // pour 64 bits 14 + 1 soit 15 caractères devraient suffire
    ...
    char* IntToAAA(int64_t n) {
       int i =15, r, q;
       str[i] = 0;
       while(n > 0) {
          q = n / 26;
          r = n - 26*q;
          n = q;
          if(r == 0) { r = 26; --n; }
         str[--i] = 64 + r; // suppose un code ASCII avec 65 = 'A' etc
       }
       return &(str[i]);
    }
    Une valeur nulle ou négative renvoie une chaîne vide ( &(str[i] pointe sur un caractère nul);

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  9. #29
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    sinon …

    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
    bool next(char col_name[static 3])
    {
        if (col_name[1]==0) {
            if (col_name[0]=='Z') {
                col_name[0]='A';
                col_name[1]='A';
            } else {
                col_name[0]++;
            }
        } else if (col_name[1]=='Z') {
            if (col_name[0]=='Z') {
                col_name[0]='A';
                col_name[1]=0;
                return false;
            } else {
                col_name[0]++;
                col_name[1]='A';
            }
        } else {
            col_name[1]++;
        }
        return true;
    }
    C'est juste un odomètre déroulé … et ça s'utilise :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char col_name[3]= {'A',0,0};
    ...
    do {
        printf("%s\n", col_name);
    } while (next(col_name));
    ...

  10. #30
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Salut,

    L’hypothèse de départ est erronée. J'ai lu le besoin et il n'est pas de "convertir un nombre x en base 26" mais de trouver la permutation lexicographique de rang x. Ce n'est donc pas un problème d'arithmétique, qui débouchera nécessairement dans une impasse, mais bel et bien d'analyse combinatoire, conf le dictionnaire. Ça se résout assez bien avec les graphes et on arrive généralement à des algorithmes de complexités O quasi-linéaires alors que celles des approches intuitives sont plutôt quadratiques. Pour ceux qui veulent en savoir plus, je vous invite à faire une recherche de unrank(ing) lexicographic permutation, parce que c'est ce que c'est, ça donnera donc de bon résultats. En français, vous pouvez essayer désordonnancement, décomposition (d'une) permutation lexicographique, les deux derniers mots étant les plus importants.

  11. #31
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut re
    Bonjour avtous.

    Citation Envoyé par kaitlyn Voir le message
    Salut,
    L’hypothèse de départ est erronée. J'ai lu le besoin et il n'est pas de "convertir un nombre x en base 26" mais de trouver la permutation lexicographique de rang x. ...
    En français, vous pouvez essayer désordonnancement, décomposition (d'une) permutation lexicographique, les deux derniers mots étant les plus importants.
    Lecture interressante. J'ai lu quelques articles. Je crois que j'ai traité quelques problèmes dans le passé usant d'algorithmes très similaires.

    Mais je penses que ce serait une incompréhension du problème en l'assimilant à ce sujet passionnant dont l'utilité est la génération de codes obeissant à une logique de succesions et surtout la recherche de toutes les combinaisons possibles de proches en proches, je l'ai fait pour corriger des erreurs d'adresses dans une base, trouver des personnes..
    Enfin je crois qu'utiliser un tel balayage pour juste une déduction arithmétique (car ça l'est), est un peu fort.

    Le code brouillon que j'ai posté hier donne la solution
    Je vais le ventiler un peu pour alleger la lecture sans commentaires.

    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
    ...
        char *ltref ="ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
        char lret [6] = { 'Z', 'X', 'A', 'Y' }, *r =lret ;
        int b = 26, s = 64 ;
        long i = 0, n = 1, nb = 0;
     
        i = strlen(lret) ;
        r+= i - 1;
        nb+= n * (*r - s) ;
        while( --i && r-- )
        {
            n *= b ;
            nb+= n * (*r - s) ;
        }
        printf("\ncol(%s) == %ld\n", lret, nb) ;
    ...
        n = nb, i = 0 ;
        while (n--)
        {
            lret[i++] = ltref[n % b] ;
            n/= b ;
        }
        // rotation dans le bon sens de lecture
        for (i/= 2, r--; i-- ; SWAP(lret[i], r[-i])) ;
     
        printf("col(%ld) == %s\n", nb, lret) ;


    Citation Envoyé par WhiteCrow Voir le message
    sinon …

    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
    bool next(char col_name[static 3])
    {
        if (col_name[1]==0) {
            if (col_name[0]=='Z') {
                col_name[0]='A';
                col_name[1]='A';
            } else {
                col_name[0]++;
            }
        } else if (col_name[1]=='Z') {
            if (col_name[0]=='Z') {
                col_name[0]='A';
                col_name[1]=0;
                return false;
            } else {
                col_name[0]++;
                col_name[1]='A';
            }
        } else {
            col_name[1]++;
        }
        return true;
    }
    C'est juste un odomètre déroulé … et ça s'utilise :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char col_name[3]= {'A',0,0};
    ...
    do {
        printf("%s\n", col_name);
    } while (next(col_name));
    ...
    Approche très séduisante en effet. N'est ce pas toujours de la logique de permutation lexicographique quelque part? En tout cas le code me plaît.

    Citation Envoyé par Guesset Voir le message
    ..
    En fait, il s'avère que c'est bien un codage par position mais sans 0 avec des chiffres an qui vont de 1 à 26 : a3.23 + a2.262 + a1.261 + a0.260. On voit tout de suite le lien avec ABCD...
    Salutations
    Juste.
    Le calcul de la valeur de sous champ d'etiquette sera donc un nb -1 implicite a chaque iteration parce que le rang d'ordre de l'indice de champ debute à 1.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  12. #32
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Des chiffres et des lettres
    Bonjour kaitlyn,
    Citation Envoyé par kaitlyn Voir le message
    ...Ce n'est donc pas un problème d'arithmétique, qui débouchera nécessairement dans une impasse...
    Sauf si mon raisonnement et l'algorithme de conversion est faux (ce qui ne serait pas une première ) la conversion est plutôt aisée. Par ailleurs, je ne vois pas comment une logique seulement lexicographique permettrait à Microsoft (et les autres) de faire dans leurs tableurs le lien entre les n° de colonnes qui figurent dans les formules et les positions effectives des cellules désignées (par balayage ?).

    Salut.
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  13. #33
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    combinatoirement il faut une fonction qui donne le rang d'une multi-combinaison. Ici la solution est simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int rank(char string[static 3]) {
        if (string[1]==0)
            return string[0]-'A';
        else
            return (string[2]-'A')*26 + (string[1]-'A') + 26;
    }
    et une autre qui à partir d'un rang donne une multi-combinaison :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    char unrank(int rank) {
        static res[]={0,0,0};
        char digits[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if (rank<26) {
            res[0]=digits[rank];
        } else {
            rank-=26;
            res[1]=digits[rank%26];
            res[0]=digits[rank/26];
        }
        return strdup(res);
    }
    Bon c'est du quick and dirty (code non vérifié, mais c'est pour donner l'idée) mais cela s'étend bien à une longueur quelconque, y compris quand chaque position peut prendre des valeurs issues d'ensembles différents, tant qu'une logique d'odomètre est respectée.

    Une bonne référence est (évidemment) Knuth avec le volume 4 du TAOCP que l'on peut consulter gratuitement dans les fascicules 2a (all n-uples), 2b (all permutations), 3a (all combinations) et 3b (all partitions).

  14. #34
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par WhiteCrow Voir le message
    combinatoirement il faut une fonction qui donne le rang d'une multi-combinaison. Ici la solution est simple :
    ...
    Helà trop simple pour marcher. En executant mentalement ta proposition, je vois qu'elle butera pour certains cas et réussira par coincidence pour d'autres.
    J'ai déjà abordé le problème sous ce même angle de reflexion l'autre jour, sans savoir pourquoi je m'obstinais pendant prês de 2 heures à essayer différents jeux d'acrobaties conditionnelles, passant à côté de la solution.
    Non je l'ai dit à demi mot, je le dis ouvertement, bien que la logique de construction de cette voie est assez jolie, elle fera une impasse en passant à côté du problème avec un nombre qui n'obeit pas, à moins d'un restriction limitative donc solution spécifique.
    Oui en restreignant les bornes, à une limite précise, on pourra faire une logique combinatoire suffisante pour couvrir les entorses arithmétiques du problème. Et chaque fois qu'on atteint un seuil de valeur auquel l'algo n'est pas préparé, il faut ajouter d'autres conditions. Pour 2 items déjà, le paramétrage que je vois n'est pas suffisant, ensuite pour 3, il faut ajuster, puis ainsi de suite. Au risque de rentrer dans une itération folle pour une broutille.
    En fait nous avons l'habitude de traiter ce cas simplement sans s'en rendre compte dans d'autres situations.
    Vois par exemple le problème d'évaluation de l'indice des sous champs du nombre à décomposer. J'ai buté en commençant avec un critère, qui n'a cessé d'évoluer avec les grandeurs croissantes. Oui c'est exponentiel.

    Il n'y a que 2 méthodes fiables, l'une coûteuse avec le hash simple modulo quotient exigeant 2-3 couches d'opérations suplémentaires et cela après la décomposition du nombre, l'autre la plus efficace est ce que je fais souvent et que beaucoup d'autres surement font dans les cas anodins : l'échappement du modulo avec n -1 en préalable avant de briser, puis +1 a la recomposition. On peut alors être sûr de ne pas mener un jeu de conditions combinatoires plus tard.
    Saluts.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  15. #35
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Citation Envoyé par NVCfrm Voir le message
    Helà trop simple pour marcher. [...]
    Ah ben oui, c'était pour donner l'idée ; mais le code était erroné. Avec un code corrigé tout fonctionne ⇒ à la 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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
     
    int rank(char string[static 3]) {
        if (string[1]==0)
            return string[0]-'A';
        else
            return (string[0]-'A')*26 + (string[1]-'A') + 26;
    }
     
    char *unrank(int rank) {
        char res[]={0,0,0};
        char digits[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if (rank<26) {
            res[0]=digits[rank];
        } else {
            rank-=26;
            res[1]=digits[rank%26];
            res[0]=digits[rank/26];
        }
        return strdup(res);
    }
     
     
    int main(void)
    {
    	for(int i=0; i<702; i++) {
    		char *res=unrank(i);
    		int crank=rank(res);
    		printf("%3d : %2s %3d\n", i, res, crank);
    		free(res);
    	}
    	return 0;
    }

    ou il faut me montrer de plus près où se situe l'erreur …

  16. #36
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Quand y en a plus...
    Bonjour,

    Puisque cestte conversation fermée est plus active que jamais, je propose le calcul général inverse de IntToAAA (quasi identique à une base numérique classique) :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char str[16}; // pour 64 bits 14 + 1 soit 15 caractères devraient suffire
    ...
    int64_t AAAToInt(char * str) {
       if(*str == 0) return 0;
       int64_t r = 0, dr = 0; 
       while(*Str != 0) {
          dr = *Str - 'A' + 1;            // Ou en général -'@'
          if(dr < 1 || dr > 26) return r; // choix de ne retourner que la partie valide
          r = r*26 + dr;                  // Si nécessaire, s'assurer que cela ne dépasse pas 2^63-1
          ++Str;
       }
       return r;
    }
    J'ai fait le choix de considérer que 0 est représenté par la chaîne vide (a l'instar de la représentation classique des 0 dits non significatifs). Un autre choix pourrait être de décaler de 1. Si je me souviens bien l'autre notation des tableurs, LC, commence par L1C1 et non L0C0, donc le 0 ne devrait pas être un problème.
    La méthode du compteur est meilleure pour afficher une séquence continue mais pas pour une conversion directe. Les deux se combinent, par exemple en cas de scroll horizontal, pour initialiser la séquence avec la conversion IntToAAA puis la gérer ensuite par comptage direct.
    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  17. #37
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par WhiteCrow Voir le message

    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
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
     
    int rank(char string[static 3]) {
        if (string[1]==0)
            return string[0]-'A';
        else
            return (string[0]-'A')*26 + (string[1]-'A') + 26;
    }
     
    char *unrank(int rank) {
        char res[]={0,0,0};
        char digits[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if (rank<26) {
            res[0]=digits[rank];
        } else {
            rank-=26;
            res[1]=digits[rank%26];
            res[0]=digits[rank/26];
        }
        return strdup(res);
    }
     
     
    int main(void)
    {
    	for(int i=0; i<702; i++) {
    		char *res=unrank(i);
    		int crank=rank(res);
    		printf("%3d : %2s %3d\n", i, res, crank);
    		free(res);
    	}
    	return 0;
    }

    ou il faut me montrer de plus près où se situe l'erreur …
    Rien à dire sur ce code ... mais.
    Puis quand on va augmenter d'un cran la portee, on va faire
    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
    30
    31
    32
    33
    34
    char *unrank_v2(int rank)
    {
    	static char res[]={0,0,0,0};
    	char digits[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    	if (rank<26) {
    		res[0]=digits[rank];
    	}
    	else if (rank < 26*26) {
    		rank-=26;
    		res[1]=digits[rank%26];
    		res[0]=digits[rank/26];
    	}
    	else {
    		rank-=26;
    		res[2]=digits[rank%26];
    		res[1]=digits[((rank-26)/26)%26];
    		res[0]=digits[(((rank-26)/26)-26)/26];
     
    	}
    	return strdup(res);
    }
     
    int rank_v2(char string[static 4])
    {
        if (string[2] == 0)
        {
            if (string[1]==0)
                return string[0]-'A';
            else
                return (string[0]-'A')*26 + (string[1]-'A') + 26;
            }
        else
            return ((string[0]-'A') * 26 + (string[1]-'A') + 26) * 26 + (string[2]-'A') + 26 ;
    }
    Ensuite 1 autre coup supplémentaire il va falloir ... non sans blagues, le code est tres joli, (quand je dis cela, c'est pour ne pas dire parfait a mes yeux dans les limites qu'il impose'), mais bon ... vous comprenez la suite.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  18. #38
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    L'idée de l'algorithme est simple :

    1. trouver la longueur de la combinaison suivant son rang ;
    2. «calculer la combinaison» = transformer un nombre en base 26 (convention A=0,B=1,,…,Z=25).


    Ce que je donne est déroulé et taillé pour des combinaison de longueur maximum 2 (la demande du PO).

    Trouver la longueur de la combinaison suivant le rang n'est pas hyper compliqué … il faut savoir ajouter des puissances de 26.
    Trouver le rang suivant la combinaison n'est pas plus compliqué, il faut ajouter au nombre en base 26 un somme de puissances de 26 qui dépend de la longueur.
    Trouver le suivant c'est faire un incrément d'odomètre, si on retombe sur 0 (que des A) avec une retenue on ajoute une position.

  19. #39
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 036
    Points : 1 917
    Points
    1 917
    Billets dans le blog
    5
    Par défaut re
    Citation Envoyé par WhiteCrow Voir le message
    ..
    Ce que je donne est déroulé et taillé pour des combinaison de longueur maximum 2 (la demande du PO)...
    Bon. Je comprends que nous ne sommes pas sur les mêmes motivations. Je dois peut être préciser pourquoi je réagissais sur un fil dejà marqué résolu. Ce n'est pas sur la demande du PO qui est d'aillleurs satisfait par une solution qui, quoi qu'on en pense satisfait le besoin contraint sur un indice max.
    De mon côté aussi comme le PO, j'ai terminé depuis le poste #27 avec l'exemple d'un code de test rapide commençant a la ligne 34, pour vérifier la simplicité de la formule.
    L'important étant de signaler qu'il n'y a pas de handicap à traiter une grandeur quelconque.

    Ainsi je réagis aux posts qui ont suivi une preoccupation qui a du vous échapper qu'on peut enoncer : Pas de limite autre que celui d'une grandeur quelconque. ET je pensais que le code que vous proposez venait en appui a cet objectif. Le code que j'apprécie d'alleurs pour sa rectitude est pour la simple raison que : avant d'adopter une classique boucle de conversion' j'ai passé par le meme style dans une premiere considération de 2 lettres avec 1 if else la chose est ok, puis j'ai pris 3 lettres.

    C'est pourquoi envisager le traitement d'une grandeur quelconque avec un déroulement algoritmique qui est identique au votre m'est apparu comme une solution lourde que je n'ai pas a envisager, alors qu'avec une bonne formule réiterée cycliquement dans un simple test de non nullité du paramètre la chose est réglée.
    Les choix du déroulement arithmetiques diffèrent, sinon c'est quasiment presque les mêmes traitements dans une boucle qu'avec une sequence de if ou select case explosive selon la grandeur.

    Comme quoi, même en arithmétique il y a différents chemins pour arriver au meme résultat cible. Genre avec 15 et 5, combien de parts de 5 faut il ajouter a 5 pour atteindre 15. La reponse 2, a différentes voies de résolution n'est ce pas.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  20. #40
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Salut,

    Il n'y a pas de bons ou de mauvais algorithmes pour peu qu'ils répondent avec justesse à la problématique, mais il n'est pas toujours possible de les tester sur toute l'étendue des possibilités et parfois il y a des surprises. À l'inverse, il y a des approches très étudiées, souvent issues des sciences, qui permettent un cheminement plus rigoureux, voire moins tortueux et qui sous certaines conditions assurent de faire mouche à tous les coups. Quelquefois aussi on construit un algorithme de manière tout à fait intuitive et au bout d'un certain temps on apprend qu'il a un nom, et ça, ça réconforte.

    Quant à ma précédente intervention, elle était juste pour faire écho à vos nécessités d'avoir un code qui prenne en compte les évolutions du besoin. Là j'espère donner une illustration de l'histoire des permutations où je fais également un parallèle avec les conversions de base puisqu'il en a été question dans cette discussion. Le code est en C, il a été écrit sur téléphone à la pause café et contient des "mots de pensée" en prévision d'une relecture, mais finalement je ne la ferai pas. C'est donc du vrac. Je viens juste de le compiler et d'ajouter un cast sauvage. Il faut savoir aussi qu'il peut se résumer à 5 lignes de codes. Si ici il en fait plus, c'est parce qu'il est détaillé.

    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
    //dummy function
    int power(int x, int y)
    {
        return (int) (pow(x, y)+0.5);
    }
     
    //dummy function
    void get_rk_from_ni(int* r, int* k, int n, int i)
    {
        for (int j= 1, m= 0; m<i; ++j) {
            *r= j;           // j: depth level
            *k= i-1-m;       // k: rank, 0 based index in the level
            m+= power(n, j); // m: i max of the previous level
        }
    }
     
    //dummy function
    void fill_p_from_rnk(int p[], int r, int n, int k)
    {
        for (int j= r; j>0; --j) {
            p[j-1]= k%n;     // filling (zero based) p[] (vector?) in reverse order with a polynomial (decomposition?) algorithm,
            k/= n;           //   it is the equivalence of the number (k)10 in base n expansion,
        }                    //   the difference is that P0(3,n) output is 000 when (0)10->n conversion output is 0.
    }
     
    //ben dummy aussi... très très dummy...
    int main()
    {
        //permutation unranking part
        // input:
        enum {n= 26};  // number of elements in a set of distinct elements.
        int i= 703;    // lexicographic depth index, starts from one.
     
        // computing intermediate values
        int r;         // permutation size, r elements from n, aka P(r,n) where r>0 and generally r<=n, it is also the depth level of the tree (graph)
        int k;         // zero based permutation rank, it is also the zero based index from the depth level of the tree graph
        get_rk_from_ni(&r, &k, n, i);
     
        // allocating and filling the output array:
        int* p=  malloc(sizeof *p * (unsigned)r); // <=> int p[r], permutation container for the unranking operations Pk(r,n).
        if (p == 0)
            return 1;
        fill_p_from_rnk(&p[0], r, n, k);
     
        // printing data:
        printf("\nPermutation Pk(r,n) with k=%d (0x%x) (o%o), r=%d, n=%d: {", k, k, k, r, n);
        for (int j= 0; j<r; ++j)
            printf("%d,", p[j]);
        puts("\b}\n");
     
        //bijection part (optional), (mapping?)
        // input:
        char S[][n]= {
              {"ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789,:!_"} // Set of n distinct elements from a list, ordered arbitrarily.
            , {"0123456789ABCDEF"} // another example with base 16 (hex) alphabet when n=16, decimal when n=10, octal for n=8, binary for n=2
            };
     
        // printing data (lexicographic sequence? string?) (bitstring?):
        for (size_t s= 0; s<(sizeof S / sizeof S[0]); ++s) {
            printf("Selected Set: %.*s\n", n, S[s]);
            printf("Bijection f of the Permutation P through the Set, aka f(P), +/- <=> to (k)10=(fP)n: ");
            char c;
            for (int j= 0; j<r; ++j)
                printf("%c", ((c= S[s][p[j]]) ? c: '?'));
            puts("\n");
        }
     
        free(p);
        return 0;
    }

    @Guesset
    Citation Envoyé par Guesset Voir le message
    je ne vois pas comment une logique seulement lexicographique permettrait à Microsoft (et les autres) de faire dans leurs tableurs le lien entre les n° de colonnes qui figurent dans les formules et les positions effectives des cellules désignées (par balayage ?).
    Je ne pense pas mais on peut associer des métadonnées aux cellules au cours de l'édition, construire une table de mappage. Disons que comme c'est une GUI on peut faire beaucoup de choses en arrière plan sans impacter l'expérience utilisateur.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Réponses: 3
    Dernier message: 03/11/2014, 17h26
  2. [VB.NET] Convertir un nombre base 10 vers 9 sans 0
    Par Dayvid dans le forum Débuter
    Réponses: 0
    Dernier message: 24/05/2013, 18h25
  3. Convertir un nombre décimal fractionnaire négatif en base 2
    Par christian79 dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 09/04/2013, 13h55
  4. Réponses: 15
    Dernier message: 14/03/2012, 15h12

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