Bonjour
Voilà : je voudrais faire un programme qui m'écrit toutes les suites de lettres possibles entre AAAAA et ZZZZZ, et qu'il stocke chaque suite dans un fichier.
Sauf qu'il faut que mon programme soit le plus rapide possible. J'ai donc faire une boucle qui incrémente la variable nb, qui contient le nombre à transformer de base 10 à base 26. Je fais donc la conversion et j'obtiens donc 6 nombres entre 0 (A) et 25 (Z). Je voudrais donc écrire dans un fichier cette lettre. Je pourrais faire 26 tests pour savoir quel est cette lettre (Si lettre = 0, écrire A, si lettre = 1, ecrire B... Mais je trouve ça un peu long, et un peu bourrin.
Je voudrais donc ajouter 65 à ce nombre, puis écrire dans mon fichier le code ascii de la lettre :
A=65
B=66
...
Ce qui ferait que je n'aurais pas de tests à effectuer.
Comment faire ?
Merci d'avance
--EDIT--
Oupss... J'ai posté trop vite.
J'arrive à faire ce que je veux faire via un tableau de char... :
L'obfuscation ? C'est quoi le rapport ? Ce n'est pas dissimuler une information sous une masse de fausses ?
En fait comme je veux avoir 6 caractères, for (char c='A' ; c<='Z' ; ++c) ne me permet pas de le faire. Sauf si on peut faire for ([inconnu] c='AAAAAA' ; c<='ZZZZZZ' ; ++c)
Est-ce possible ? Si oui comment ?
Merci d'avance
--EDIT--
Je pourrais utiliser ta technique en imbriquant ces conditions... Je vais regarder. Mais si vous avez une solution pour le faire directement pour optimiser le code, je suis prenant !
Obfusquer, c'est écrire 65 au lieu de 'A'. 65 est une constante magique que tout le monde ne connaitra pas par coeur, et en plus c'est un nombre. 'A', ben ... c'est un caractère. C'est sémantiquement très fort et sans le moindre doute quant à nos intention. Et en plus, c'est facile à maintenir.
Tu devras réaliser 26^6 itérations. Donc, avoir 6 boucles imbriquées est la solution canonique.
Tu pourras très certainement l'émuler avec un curseur à déplacer, mais de nouveau, ce sera de l'obfuscation : un code plus compliqué, incompréhensible au premier abord, et certainement plus lent par la même occasion.
Je vais essayer ce que tu as mis, mais entre temps j'ai trouvé ça (en bas : conversion depuis d'autres types.)
Ce qui me donne à la fin ce code qui marche plutôt bien :
J'ai essayé plusieurs syntaxes de string(a)+b, mais rien... (string(a+b), string(a)+string(b)...)
Une idée ?
Note : j'aimerais trouver une autre méthode que celle que j'ai trouvée car à la compilation j'ai un message qui me dit que cette librairie va être remplacée... Donc si vous connaissez celle qui la remplace, dites le moi
/usr/include/c++/4.3/backward/backward_warning.h:33:2: warning: #warning This file includes at least one deprecated or antiquated header which may be removed without further notice at a future date. Please use a non-deprecated interface with equivalent functionality instead. For a listing of replacement headers and interfaces, consult the file backward_warning.h. To disable this warning use -Wno-deprecated.
Merci d'avance
--EDIT2--
#include <sstream> (stringstream) à l'air d'être mieux acceptée. Après, si vous avez des informations sur le technique de lmghs dites le moi
Et merci beaucoup lmghs pour l'aide que tu m'as apporté !
Bon, il faut pas être pressé... (en 8mn il a à peine fini le A pour première lettre.) et si mes calculs sont bon (bon, je les ai fait à 22h hier soir, donc il sont peux être faux) il prendra environ 1.2Go...
Par contre, peux-tu expliquer à quoi correspond les param. de string(1,a) ? A quoi correspond le 1 ? il faut donc faire string(1,a)+string(1,b) si j'ai bien compris.
Et pourrais-tu m'expliquer comment fonctionne ton 2eme programme ? Je ne comprend même pas la première ligne : 6 /*, ' ' ?*/. Les /* */ sont juste des commentaires où ils font parti intégrale de la chaine ? Et à quoi correspond le 6 ? Et pourquoi est-ce que tu considère res comme un tableau ? J'avoue que je suis un peu perdu...
Les commentaires, correspondent à un doute de ma part. Je n'ai pas l'impression qu'il existe une surcharge du constructeur qui ne prennent qu'un seul argument => string(6, 'A') ira très bien.
Le 6 sert à dire que la chaine fera donc 6 caractères. Et std::string met à disposition un opérateur d'accès indexé qui renvoie une référence vers le n-ième caractère demandé.
J'aurai tout aussi bien pu écrire: "for ( res[0] = 'A' ; res[0] <= 'Z' ; ++res[0])" six fois.
Cela évite de construire une chaine à chaque itération.
Accessoirement, le fichier fera plutôt entre 2 et 2.3 Go (26^6 * (6+1 +1 si format dos) / 1024 /1024 -> 2062/23xx)
Obfusquer, c'est écrire 65 au lieu de 'A'. 65 est une constante magique que tout le monde ne connaitra pas par coeur, et en plus c'est un nombre. 'A', ben ... c'est un caractère. C'est sémantiquement très fort et sans le moindre doute quant à nos intention. Et en plus, c'est facile à maintenir.
Tu devras réaliser 26^6 itérations. Donc, avoir 6 boucles imbriquées est la solution canonique.
Tu pourras très certainement l'émuler avec un curseur à déplacer, mais de nouveau, ce sera de l'obfuscation : un code plus compliqué, incompréhensible au premier abord, et certainement plus lent par la même occasion.
Il me semble aussi que c'est une histoire de portabilité, une machine pouvant posséder une table ASCII différente.
void inscrire_liste_chaines(std::ostream & out) /* tous les flux d'écriture héritent de ostream (si je ne me trompe pas) */
{
#define N 6 /* définit le nombre de caractères à mettre */
char tab[N + 1]; /* un tableau pour retenir la combinaison actuelle */
/* on remplit ce tableau */
for(unsigned int i = 0;i<N;i++)
tab[i] = 'a';
tab[N] = '\0';
/* on fait la boucle jusqu'à ce que le premier caractère ne soit plus une majuscule */
while(tab[0] <= 'z')
{
/* on affiche dans n'importe quel flux la chaine */
out << tab << std::endl;
/* on incrémente le dernier caractère */
tab[N-1]++;
/* si on a un caractère supérieur à Z, on le fait revenir à A en augmentant la taille du précédent */
for(unsigned int i = N-1;i > 0;i--)
{
if(tab[i] > 'z')
{
tab[i] = 'a';
tab[i-1]++;
}
else
break;
}
}
#undef N
}
On aura même la liste dans l'ordre croissant.
Si on veut afficher la liste dans plusieurs flux, il suffit de modifier très légèrement la fonction.
EDIT : modification du code pour avoir des minuscules.
Et n'oublie pas qu'il est plus rapide d'écrire dans un fichier que d'écrire dans std::cout (car ça doit être affiché à l'écran immédiatement).
Petite info : en 5 minutes qu'il tourne chez moi, il a rempli près de 300 Mio.
Moche mouais. Pas évident.
Tout le monde ne va pas rentrer dedans aussi facilement. De plus, je ne serai pas surpris de constater un petit avantage de rapidité pour la version à 6 boucles.
Les réinitialisations et incrémentations sont cachées dans les boucles for. Si on regarde, on verra que je fais exactement les mêmes opérations. Par ailleurs, je remplis le tampon en prenant 6 caractères à la fois.
Par ailleurs, et je l'ai déjà dit, l'opération la plus coûteuse est la mise dans un flux de chaque donnée. Il serait donc bon d'optimiser cette fonction pour le résultat attendu.
Je pourrais donc réécrire la ligne :
out << tab << std::endl;
en écrivant :
out.write(tab,N + 1);
Evidemment, il faudra avoir modifié la case tab[N] en '\n' au lieu de '\0' (write écrit les N + 1 premiers caractères de tab, sans vérification de '\0').
Pour ceux qui n'auraient pas suivi :
void inscrire_liste_chaines(std::ostream & out) /* tous les flux d'écriture héritent de ostream (si je ne me trompe pas) */
{
unsigned int const N = 6; /* définit le nombre de caractères à mettre */
char tab[N + 1]; /* un tableau pour retenir la combinaison actuelle */
/* on remplit ce tableau */
for(unsigned int i = 0;i<N;i++)
tab[i] = 'a';
tab[N] = '\n';
/* on fait la boucle jusqu'à ce que le premier caractère ne soit plus une majuscule */
while(tab[0] <= 'z')
{
/* on affiche dans n'importe quel flux la chaine */
out.write(tab,N+1);
/* on incrémente le dernier caractère */
tab[N-1]++;
/* si on a un caractère supérieur à Z, on le fait revenir à A en augmentant la taille du précédent */
for(unsigned int i = N-1;i > 0;i--)
{
if(tab[i] > 'z')
{
tab[i] = 'a';
tab[i-1]++;
}
else
break;
}
}
}
Je vais tester sous peu pour voir si l'exécution est plus rapide. (pour information, ma première exécution a duré environ 2 164 secondes)
EDIT pour le message plus haut : pourquoi voit-on tout de suite une tentative de piratage quand quelque chose s'y rapproche ?
Imaginons que je veuille coder un cryptage RSA. On va tout de suite me dire "c'est pour faire l'attaque par le milieu ?". Ca n'aurait absolument aucun sens.
EDIT : savoir ce qui prend le plus de temps de calculs permet d'améliorer nettement la vitesse d'exécution : 512 secondes (moins de 10 minutes) au lieu de 2 164 (environ 35 minutes).
Les réinitialisations et incrémentations sont cachées dans les boucles for. Si on regarde, on verra que je fais exactement les mêmes opérations. Par ailleurs, je remplis le tampon en prenant 6 caractères à la fois.
Par ailleurs, et je l'ai déjà dit, l'opération la plus coûteuse est la mise dans un flux de chaque donnée. Il serait donc bon d'optimiser cette fonction pour le résultat attendu.
Je pourrais donc réécrire la ligne :
out << tab << std::endl;
en écrivant :
out.write(tab,N + 1);
Evidemment, il faudra avoir modifié la case tab[N] en '\n' au lieu de '\0' (write écrit les N + 1 premiers caractères de tab, sans vérification de '\0').
Pour ceux qui n'auraient pas suivi :
void inscrire_liste_chaines(std::ostream & out) /* tous les flux d'écriture héritent de ostream (si je ne me trompe pas) */
{
unsigned int const N = 6; /* définit le nombre de caractères à mettre */
char tab[N + 1]; /* un tableau pour retenir la combinaison actuelle */
/* on remplit ce tableau */
for(unsigned int i = 0;i<N;i++)
tab[i] = 'a';
tab[N] = '\n';
/* on fait la boucle jusqu'à ce que le premier caractère ne soit plus une majuscule */
while(tab[0] <= 'z')
{
/* on affiche dans n'importe quel flux la chaine */
out.write(tab,N+1);
/* on incrémente le dernier caractère */
tab[N-1]++;
/* si on a un caractère supérieur à Z, on le fait revenir à A en augmentant la taille du précédent */
for(unsigned int i = N-1;i > 0;i--)
{
if(tab[i] > 'z')
{
tab[i] = 'a';
tab[i-1]++;
}
else
break;
}
}
}
Je vais tester sous peu pour voir si l'exécution est plus rapide. (pour information, ma première exécution a duré environ 2 164 secondes)
EDIT pour le message plus haut : pourquoi voit-on tout de suite une tentative de piratage quand quelque chose s'y rapproche ?
Imaginons que je veuille coder un cryptage RSA. On va tout de suite me dire "c'est pour faire l'attaque par le milieu ?". Ca n'aurait absolument aucun sens.
EDIT : savoir ce qui prend le plus de temps de calculs permet d'améliorer nettement la vitesse d'exécution : 512 secondes (moins de 10 minutes) au lieu de 2 164 (environ 35 minutes).
Merci pour ce code ! il est très formateur. J'avais pensé à faire un code de ce type là mais j'avoue que j'avais peur que ça se complique. J'ai bien analysé le code et j'ai tout compris !
Merci beaucoup pour ce code très simple à paramétrer, et plus rapide de surcroit
Et comment as-tu fais pour chronométrer ? Tu as mis une variable qui stocke la variable de début, puis un pour la variable de fin et tu compares les 2 ?
Les réinitialisations et incrémentations sont cachées dans les boucles for. Si on regarde, on verra que je fais exactement les mêmes opérations.
Pas de la même façon. Avec celle-ci, je ne suis pas sûr que le compilo puisse aussi bien exploiter le pipeline.
C'est à dire ? Qu'est-ce que tu entends par pipeline ? Ce n'est pas lorsque l'on met bout à bout plusieurs programmes ? En quoi est-ce que ca gène ?
Et j'ai essayé la première version du programme à Alienore, et en fait elle à l'air plus longue (presque 1h pour seulement 5 caractères...). Je vais essayer l'autre version après.
Donc en gros, si j'ai bien compris, pour le programme avec plein de boucle, il est plus rapide car le processeur peut pré calculer sur plusieurs "étages" alors que pour le 2eme programme, il est obligé de faire ligne par ligne et donc ne mobilise qu'une seule ligne ?
C'est ça ? Si oui, qu'est-ce qui détermine si tel programme facilite le pipeline et quel autre non ?
C'est vrai que ton code est sans contexte beaucoup plus paramétrable qu'avec les boucles imbriquées. C'est ce qui en fait sa force.
Pour ce qui est de la rapidité, il faudra que je compare les 2 systèmes.
PS : et j'ai fait tourner le programme avec les boucles sous un windows XP du lycée, il a écrit les 2.3 Go en environ 2heures sur le serveur. (je l'ai lancé avant les 2 heures de cours de français et j'ai mis le programme dans le systray Lorsque je suis revenu, il en était à la fin des x). Le fichier fait bien 2.3 Go comme tu l'avais dit : je n'avais pas compté le caractère entré -> seulement x6 au lieu de x7...
Citation : lmghs
C'est vrai. Pour faire la même chose avec les imbrications, il faut sortir de la meta-prog (simple).
Qu'est-ce que tu entends par "sortir de la meta-prog" ? C'est faire un programme beaucoup plus compliqué ?
Ok ! En gros la métaprogrammation c'est faire un programme qui génère lui même un autre programme.
Ouaaaa !
Dis, j'ai essayé le code d'Alienore sur un autre ordinateur : ubuntu, 3 coeurs, et il m'a couché les 2Go en 42 secondes !!! J'y crois pas ! Et lorsque je fais un cat sur ce fichier, l'affichage à lui tout seul met bien plus longtemps que 42 secondes !!!
Incroyable ! Je vais essayer de tester les autres.
Par contre lmghs, je ne comprends pas ton programme... Qu'est-ce que loop ? J'ai cherché un peu sur internet et je ne trouve rien dessus... C'est le nom d'une structure ? A quoi correspondent les < > sur Loop<N-1, M+1> ? Et à quoi sert une Template ? D'après ce que j'ai peu voir sur le net, ça sert à pouvoir utiliser plusieurs type de variable sans avoir besoin de recréer une nouvelle fonction pour ça ? Et tu parles de foncteurs... Késako ?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
* Un wrapper C++ pour sqlite * Une alternative a boost units