Tous les prétextes sont bons pour faire du C : compléter la grille 4x4
ci-dessous par des chiffres décimaux (deux zéros sont déjà placés) en
sorte que tous les nombres de 4 chiffres (lus de la gauche vers la
droite ou de haut en bas) qui apparaissent soient des multiples de 97 :
0XXX
XX0X
XXXX
XXXX
Il n'y a pas que la solution triviale. Bon amusement.
En théorie rien. En pratique, le fonctionnement des compilos multi-plateforme, c'est de faire d'abord un "pseudo-code", de l'optimiser, puis de faire l'ASM cible, éventuellement optimisé encore. Le coup de l'évaluation, je pense que c'est fait dans le pseudo-code. Mais bon...
Tu as souvent plusieurs niveaux de descriptions et les optimisations sont faites au niveau ou elles sont le plus facile/elles apportent le plus. L'evaluation d'expressions constantes est vraisemblablement faite sur le tout premier niveau -- peut-etre meme pendant sa construction parce qu'il y a des erreurs qui doivent etre detectees qui dependent de l'evaluation de certaines d'entre elles -- et possiblement par la suite a nouveau (parce qu'on est arrive a montrer qu'il y a des variables qui sont en fait des constrantes et donc qu'on peut se servir de leur valeur).
A+
-- Jean-Marc FAQ de fclc: http://www.levenez.com/lang/c/faq Site de usenet-fr: http://www.usenet-fr.news.eu.org
Marc Boyer <Marc.Boyer@cert.onera.fr.invalid> writes:
En théorie rien. En pratique, le fonctionnement des compilos
multi-plateforme, c'est de faire d'abord un "pseudo-code", de
l'optimiser, puis de faire l'ASM cible, éventuellement optimisé
encore. Le coup de l'évaluation, je pense que c'est fait dans
le pseudo-code. Mais bon...
Tu as souvent plusieurs niveaux de descriptions et les optimisations sont
faites au niveau ou elles sont le plus facile/elles apportent le plus.
L'evaluation d'expressions constantes est vraisemblablement faite sur le
tout premier niveau -- peut-etre meme pendant sa construction parce qu'il y
a des erreurs qui doivent etre detectees qui dependent de l'evaluation de
certaines d'entre elles -- et possiblement par la suite a nouveau (parce
qu'on est arrive a montrer qu'il y a des variables qui sont en fait des
constrantes et donc qu'on peut se servir de leur valeur).
A+
--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
En théorie rien. En pratique, le fonctionnement des compilos multi-plateforme, c'est de faire d'abord un "pseudo-code", de l'optimiser, puis de faire l'ASM cible, éventuellement optimisé encore. Le coup de l'évaluation, je pense que c'est fait dans le pseudo-code. Mais bon...
Tu as souvent plusieurs niveaux de descriptions et les optimisations sont faites au niveau ou elles sont le plus facile/elles apportent le plus. L'evaluation d'expressions constantes est vraisemblablement faite sur le tout premier niveau -- peut-etre meme pendant sa construction parce qu'il y a des erreurs qui doivent etre detectees qui dependent de l'evaluation de certaines d'entre elles -- et possiblement par la suite a nouveau (parce qu'on est arrive a montrer qu'il y a des variables qui sont en fait des constrantes et donc qu'on peut se servir de leur valeur).
A+
-- Jean-Marc FAQ de fclc: http://www.levenez.com/lang/c/faq Site de usenet-fr: http://www.usenet-fr.news.eu.org
Jean-Marc Bourguet
Erwan David writes:
Marc Boyer écrivait :
> > Oui et non. > Dans le cas où n provient d'une entrée utilisateur, le compilo ne > peut pas l'évaluer, car il ne connait pas la valeur. Mais il sait > transformer ton code > for(int i=0 ; i < 3*n ; i+= 3){ > ... > } > en > const int n3 = 3*n; > for(int i=0 ; i < n3 ; i+= 3){ > .... > }
Attention cette optimisation n'est pas valide si on change la valeur de n dans le corps de la boucle. (Ou alors je me trompe et c'est cette modification qui provoque un UB ?)
Tu ne te trompes pas.
-- Jean-Marc FAQ de fclc: http://www.levenez.com/lang/c/faq Site de usenet-fr: http://www.usenet-fr.news.eu.org
Erwan David <erwan@rail.eu.org> writes:
Marc Boyer <Marc.Boyer@cert.onera.fr.invalid> écrivait :
>
> Oui et non.
> Dans le cas où n provient d'une entrée utilisateur, le compilo ne
> peut pas l'évaluer, car il ne connait pas la valeur. Mais il sait
> transformer ton code
> for(int i=0 ; i < 3*n ; i+= 3){
> ...
> }
> en
> const int n3 = 3*n;
> for(int i=0 ; i < n3 ; i+= 3){
> ....
> }
Attention cette optimisation n'est pas valide si on change la valeur de
n dans le corps de la boucle. (Ou alors je me trompe et c'est cette
modification qui provoque un UB ?)
Tu ne te trompes pas.
--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
> > Oui et non. > Dans le cas où n provient d'une entrée utilisateur, le compilo ne > peut pas l'évaluer, car il ne connait pas la valeur. Mais il sait > transformer ton code > for(int i=0 ; i < 3*n ; i+= 3){ > ... > } > en > const int n3 = 3*n; > for(int i=0 ; i < n3 ; i+= 3){ > .... > }
Attention cette optimisation n'est pas valide si on change la valeur de n dans le corps de la boucle. (Ou alors je me trompe et c'est cette modification qui provoque un UB ?)
Tu ne te trompes pas.
-- Jean-Marc FAQ de fclc: http://www.levenez.com/lang/c/faq Site de usenet-fr: http://www.usenet-fr.news.eu.org
Antoine Leca
En news:49221b72$0$1135$, candide va escriure:
Antoine Leca a écrit :
En news:491f4f99$0$14922$, candide va escriure:
-ed- a écrit :
#define BORNE (10*10*10) Mais c'est strictement équivallent à 1000, car une expression constante est évaluée par le compilateur.
Non, on en a discuté dans un fil précédent, la norme ne garantit rien.
On a pas dû lire le même fil, alors.
Je te cite :
Antoine Leca a écrit :
En news:49172a5f$0$17384$, candide va escriure:
Ai-je une quelconque garantie que l'expression A*B ne sera pas réévaluée à chaque tour de boucle pendant l'exécution ?
Garantie formelle, non.
Je persiste et signe. Il n'y a pas de garantie formelle pour la proposition (_prise dans son ensemble_, savoir si l'expression est évaluée à chaque tour) juste ci-dessus.
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Mais si on cesse de pinailler, oui, la norme garantit bien que la *valeur* de BORNE sera 10000.
Je ne dis pas le contraire. Le problème n'est pas la valeur.
Bah, dans ce fil, si, le problème, enfin ce que voulait exprimer (à mon sens) Emmanuel, c'est bien de la valeur dont on parlait.
Le problème est que je ne souhaite pas que cette valeur soit recalculée à chaque tour de boucle
Comme j'ai déjà eu l'occasion de l'expliquer dans l'autre fil, te biles pas pour cela. En l'occurence le problème n'existe pas (aucun compilateur en mode d'exploitation normal ne fera pas le calcul à chaque tour); et il est même possible de rencontrer des compilateurs qui vont faire disparaître complètement la moindre instance de BORNE. Par exemple, si j'ai compris le fil, un compilateur un peu intelligent peut remplacer le code que tu as fourni sous réserves des correction pertinentes signalées, par une suite d'appel à puts() avec les « solutions » du casse-tête : c'est conforme à la norme.
Pour une question de lisibilité, tu penses bien que je préfèrerais écrire
#define BASE 10 #define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
J'en profite pour jeter un coup d'oeil à ce que disent Kernighan & Pike dans leur chapitre sur l'optimisation. Et quelle n'est pas alors ma surprise de voir (page 179) qu'ils écrivent :
for (i=0; i< 3*n; i+=3) { /* Déroulement classique de boucle */ }
J'avoue que le 3*n dans l'expression de contrôle de la boucle me laisse plus que perplexe: on n'a aucune garantie que ce produit 3*n n'est pas recalculé n fois, si ?
On s'en moque. Ici ce n'est pas fr.comp.chasser-le-microcycle-de-cpu.
Par exemple, sur une machine où les long font 3 int (resp. 48 et 16 bits, par exemple), et si i sert à indexer un tableau d'int, tu va avoir des compilateurs qui vont automatiquement remplacer ta boucle par
long *p; for( p=(long*)&tableau[0]; p<constante; ++p) {
Mais je le répète : ce n'est pas important. Le jour où tu chercheras vraiment à améliorer les performances de ton programme, d'abord tu choisiras un environnement de développement qui donne de bons résultats sur la classe de programme qui t'importe, et ensuite tu utiliseras les outils dédiés à l'optimisation, au premier rang desquels il y aura les analyseurs statiques ou dynamiques pour déterminer les portions de code à analyser ; ensuite tu laissera faire l'optimiseur, et normalement il va dégager purement et simplement la boucle... D'ici là, le plus important c'est de garder le code le plus lisible possible, afin de finir de le mettre au point, pour qu'il puisse donner un résultat correct même s'il lui faut deux ou trois fois plus de temps qu'en environnement de production.
Antoine
En news:49221b72$0$1135$426a74cc@news.free.fr, candide va escriure:
Antoine Leca a écrit :
En news:491f4f99$0$14922$426a74cc@news.free.fr, candide va escriure:
-ed- a écrit :
#define BORNE (10*10*10)
Mais c'est strictement équivallent à 1000, car une expression
constante est évaluée par le compilateur.
Non, on en a discuté dans un fil précédent, la norme ne garantit
rien.
On a pas dû lire le même fil, alors.
Je te cite :
Antoine Leca a écrit :
En news:49172a5f$0$17384$426a74cc@news.free.fr, candide va escriure:
Ai-je une quelconque garantie que l'expression A*B ne sera pas
réévaluée à chaque tour de boucle pendant l'exécution ?
Garantie formelle, non.
Je persiste et signe. Il n'y a pas de garantie formelle pour la proposition
(_prise dans son ensemble_, savoir si l'expression est évaluée à chaque
tour) juste ci-dessus.
Mais *il y a* des garanties concernant le sujet global des expressions
constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant
5, le morceau de code C
A*B
vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de
priorité supérieur à celle de *).
Mais si on cesse de pinailler, oui, la norme garantit bien que la
*valeur* de BORNE sera 10000.
Je ne dis pas le contraire. Le problème n'est pas la valeur.
Bah, dans ce fil, si, le problème, enfin ce que voulait exprimer (à mon
sens) Emmanuel, c'est bien de la valeur dont on parlait.
Le problème est que je ne souhaite pas que cette valeur soit
recalculée à chaque tour de boucle
Comme j'ai déjà eu l'occasion de l'expliquer dans l'autre fil, te biles pas
pour cela. En l'occurence le problème n'existe pas (aucun compilateur en
mode d'exploitation normal ne fera pas le calcul à chaque tour); et il est
même possible de rencontrer des compilateurs qui vont faire disparaître
complètement la moindre instance de BORNE.
Par exemple, si j'ai compris le fil, un compilateur un peu intelligent peut
remplacer le code que tu as fourni sous réserves des correction pertinentes
signalées, par une suite d'appel à puts() avec les « solutions » du
casse-tête : c'est conforme à la norme.
Pour une question de lisibilité, tu penses bien que je préfèrerais
écrire
#define BASE 10
#define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
J'en profite pour jeter un coup d'oeil à ce que disent Kernighan &
Pike dans leur chapitre sur l'optimisation. Et quelle n'est pas alors
ma surprise de voir (page 179) qu'ils écrivent :
for (i=0; i< 3*n; i+=3)
{
/*
Déroulement classique de boucle
*/
}
J'avoue que le 3*n dans l'expression de contrôle de la boucle me
laisse plus que perplexe: on n'a aucune garantie que ce produit 3*n
n'est pas recalculé n fois, si ?
On s'en moque. Ici ce n'est pas fr.comp.chasser-le-microcycle-de-cpu.
Par exemple, sur une machine où les long font 3 int (resp. 48 et 16 bits,
par exemple), et si i sert à indexer un tableau d'int, tu va avoir des
compilateurs qui vont automatiquement remplacer ta boucle par
long *p;
for( p=(long*)&tableau[0]; p<constante; ++p) {
Mais je le répète : ce n'est pas important.
Le jour où tu chercheras vraiment à améliorer les performances de ton
programme, d'abord tu choisiras un environnement de développement qui donne
de bons résultats sur la classe de programme qui t'importe, et ensuite tu
utiliseras les outils dédiés à l'optimisation, au premier rang desquels il y
aura les analyseurs statiques ou dynamiques pour déterminer les portions de
code à analyser ; ensuite tu laissera faire l'optimiseur, et normalement il
va dégager purement et simplement la boucle...
D'ici là, le plus important c'est de garder le code le plus lisible
possible, afin de finir de le mettre au point, pour qu'il puisse donner un
résultat correct même s'il lui faut deux ou trois fois plus de temps qu'en
environnement de production.
#define BORNE (10*10*10) Mais c'est strictement équivallent à 1000, car une expression constante est évaluée par le compilateur.
Non, on en a discuté dans un fil précédent, la norme ne garantit rien.
On a pas dû lire le même fil, alors.
Je te cite :
Antoine Leca a écrit :
En news:49172a5f$0$17384$, candide va escriure:
Ai-je une quelconque garantie que l'expression A*B ne sera pas réévaluée à chaque tour de boucle pendant l'exécution ?
Garantie formelle, non.
Je persiste et signe. Il n'y a pas de garantie formelle pour la proposition (_prise dans son ensemble_, savoir si l'expression est évaluée à chaque tour) juste ci-dessus.
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Mais si on cesse de pinailler, oui, la norme garantit bien que la *valeur* de BORNE sera 10000.
Je ne dis pas le contraire. Le problème n'est pas la valeur.
Bah, dans ce fil, si, le problème, enfin ce que voulait exprimer (à mon sens) Emmanuel, c'est bien de la valeur dont on parlait.
Le problème est que je ne souhaite pas que cette valeur soit recalculée à chaque tour de boucle
Comme j'ai déjà eu l'occasion de l'expliquer dans l'autre fil, te biles pas pour cela. En l'occurence le problème n'existe pas (aucun compilateur en mode d'exploitation normal ne fera pas le calcul à chaque tour); et il est même possible de rencontrer des compilateurs qui vont faire disparaître complètement la moindre instance de BORNE. Par exemple, si j'ai compris le fil, un compilateur un peu intelligent peut remplacer le code que tu as fourni sous réserves des correction pertinentes signalées, par une suite d'appel à puts() avec les « solutions » du casse-tête : c'est conforme à la norme.
Pour une question de lisibilité, tu penses bien que je préfèrerais écrire
#define BASE 10 #define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
J'en profite pour jeter un coup d'oeil à ce que disent Kernighan & Pike dans leur chapitre sur l'optimisation. Et quelle n'est pas alors ma surprise de voir (page 179) qu'ils écrivent :
for (i=0; i< 3*n; i+=3) { /* Déroulement classique de boucle */ }
J'avoue que le 3*n dans l'expression de contrôle de la boucle me laisse plus que perplexe: on n'a aucune garantie que ce produit 3*n n'est pas recalculé n fois, si ?
On s'en moque. Ici ce n'est pas fr.comp.chasser-le-microcycle-de-cpu.
Par exemple, sur une machine où les long font 3 int (resp. 48 et 16 bits, par exemple), et si i sert à indexer un tableau d'int, tu va avoir des compilateurs qui vont automatiquement remplacer ta boucle par
long *p; for( p=(long*)&tableau[0]; p<constante; ++p) {
Mais je le répète : ce n'est pas important. Le jour où tu chercheras vraiment à améliorer les performances de ton programme, d'abord tu choisiras un environnement de développement qui donne de bons résultats sur la classe de programme qui t'importe, et ensuite tu utiliseras les outils dédiés à l'optimisation, au premier rang desquels il y aura les analyseurs statiques ou dynamiques pour déterminer les portions de code à analyser ; ensuite tu laissera faire l'optimiseur, et normalement il va dégager purement et simplement la boucle... D'ici là, le plus important c'est de garder le code le plus lisible possible, afin de finir de le mettre au point, pour qu'il puisse donner un résultat correct même s'il lui faut deux ou trois fois plus de temps qu'en environnement de production.
Antoine
candide
Antoine Leca a écrit :
Pour une question de lisibilité, tu penses bien que je préfèrerais écrire
#define BASE 10 #define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
OK, je ne vais pas me priver, avec vos explications et les tiennes en particulier, me voilà rassuré.
D'ici là, le plus important c'est de garder le code le plus lisible
Pour moi la lisibilité est capitale.
Antoine Leca a écrit :
Pour une question de lisibilité, tu penses bien que je préfèrerais
écrire
#define BASE 10
#define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
OK, je ne vais pas me priver, avec vos explications et les tiennes en
particulier, me voilà rassuré.
D'ici là, le plus important c'est de garder le code le plus lisible
Pour une question de lisibilité, tu penses bien que je préfèrerais écrire
#define BASE 10 #define BORNE (BASE*BASE*BASE*BASE)
Et bien fais-le !
OK, je ne vais pas me priver, avec vos explications et les tiennes en particulier, me voilà rassuré.
D'ici là, le plus important c'est de garder le code le plus lisible
Pour moi la lisibilité est capitale.
candide
Jean-Marc Bourguet a écrit :
candide writes:
Comment savoir si les constantes sont évaluées à la compilation ?
On va reprendre d'une autre maniere.
Toute la definition du C90 est concue pour que certaines expressions entieres soient evaluees a la compilation (les deux exemples qui me viennent a l'esprit sont: les expressions controlant le preprocesseur et la taille des tableaux) parce qu'elles ne peuvent utiliser que des valeurs connues a la compilation.
Je suis un peu dur à la détente mais grâce à cette formulation je viens enfin de comprendre ce que tu t'efforçais de m'expliquer depuis plusieurs fils.
Merci.
Jean-Marc Bourguet a écrit :
candide <candide@free.invalid> writes:
Comment savoir si les constantes sont évaluées à la compilation ?
On va reprendre d'une autre maniere.
Toute la definition du C90 est concue pour que certaines expressions
entieres soient evaluees a la compilation (les deux exemples qui me
viennent a l'esprit sont: les expressions controlant le preprocesseur et la
taille des tableaux) parce qu'elles ne peuvent utiliser que des valeurs
connues a la compilation.
Je suis un peu dur à la détente mais grâce à cette formulation je viens
enfin de comprendre ce que tu t'efforçais de m'expliquer depuis
plusieurs fils.
Comment savoir si les constantes sont évaluées à la compilation ?
On va reprendre d'une autre maniere.
Toute la definition du C90 est concue pour que certaines expressions entieres soient evaluees a la compilation (les deux exemples qui me viennent a l'esprit sont: les expressions controlant le preprocesseur et la taille des tableaux) parce qu'elles ne peuvent utiliser que des valeurs connues a la compilation.
Je suis un peu dur à la détente mais grâce à cette formulation je viens enfin de comprendre ce que tu t'efforçais de m'expliquer depuis plusieurs fils.
Merci.
Vincent Lefevre
Dans l'article , Jean-Marc Bourguet écrit:
gcc fait des optimisations autrement poussees (pour commencer l'evaluation des expressions flottantes
GCC va d'ailleurs trop loin dans les optimisations:
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :) Mais évidemment, faut pas faire ce genre de chose.
Dans l'article <gfuvmm$3ep$1@shakotay.alphanet.ch>,
Antoine Leca <root@localhost.invalid> écrit:
Mais *il y a* des garanties concernant le sujet global des expressions
constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant
5, le morceau de code C
A*B
vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de
priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :) Mais évidemment,
faut pas faire ce genre de chose.
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :) Mais évidemment, faut pas faire ce genre de chose.
En news:20081121005254$, Vincent Lefevre va escriure:
Dans l'article <gfuvmm$3ep$, Antoine Leca écrit:
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :)
Je *savais* qu'il y aurait quelqu'un pour trouver un truc tordu qui viendrait gâcher la limpidité de l'explication.
Antoine
En news:20081121005254$1154@prunille.vinc17.org, Vincent Lefevre va
escriure:
Dans l'article <gfuvmm$3ep$1@shakotay.alphanet.ch>,
Antoine Leca <root@localhost.invalid> écrit:
Mais *il y a* des garanties concernant le sujet global des
expressions constantes. En particulier, il est _garanti_ que pour A
valant 2 et B valant 5, le morceau de code C
A*B
vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de
priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :)
Je *savais* qu'il y aurait quelqu'un pour trouver un truc tordu qui
viendrait gâcher la limpidité de l'explication.
En news:20081121005254$, Vincent Lefevre va escriure:
Dans l'article <gfuvmm$3ep$, Antoine Leca écrit:
Mais *il y a* des garanties concernant le sujet global des expressions constantes. En particulier, il est _garanti_ que pour A valant 2 et B valant 5, le morceau de code C A*B vaut TOUJOURS 10. TOUJOURS.
(sauf évidemment si tu me rajoutes devant ou derrière un opérateur de priorité supérieur à celle de *).
Sauf aussi si A ou B est une macro, e.g. 1+1 pour A. :)
Je *savais* qu'il y aurait quelqu'un pour trouver un truc tordu qui viendrait gâcher la limpidité de l'explication.