OVH Cloud OVH Cloud

Decalages d'un nombre de bits pouvant etre >= a la taille du type

134 réponses
Avatar
Vincent Lefevre
J'ai besoin de faire un décalage vers la droite sur un type entier
(disons non signé) générique (i.e. défini par typedef) d'un certain
nombre constant de bits. Le problème est que ce nombre de bits peut
être supérieur ou égal à la taille du type en question. Une idée
sur la façon de faire ça efficacement sans obtenir de comportement
indéfini et sans passer par un outil du style "configure"?

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

10 réponses

Avatar
Antoine Leca
En 20041007115911$, Vincent Lefevre va escriure:
Dans l'article <ck0fuf$q8h$,
Antoine Leca écrit:

Autrement dit, si le comportement indéfini est dans du code non
évalué, [...]


Mais si le comportement indéfini est dans du code évalué à la
traduction (cf 6.6#2, ce qui est le cas qui me préoccupe)?


Est-il évalué, ou non ?

Si oui, tu as comportement indéfini. Si en plus le compilo peut le détecter
à translation (traduction) et qu'il est méchant, il va the fabriquer des
dragons (s'il et gentil, il va te le signaler). Sinon, tu as le cas
classique (ça marche jusqu'au jour où cela ne marche plus).

Sinon, le comportement indéfini ne doit pas empêcher la fabrication de
l'exécutable, pas plus que cela ne doit empêcher l'exécution correcte du
programme.


Exemple caricatural:

#ifndef O
#define O 0
#endif

int main(void) {
return O ? 0/0 : 0;
}

$ gcc -W -Wall -pedantic -stdÉ9 fclc.c

$ ./a.out

$ gcc -W -Wall -pedantic -stdÉ9 fclc.c -DO
fclc.c: In function `main':
fclc.c:6: warning: division by zero

$ ./a.out
[ Votre correspondant n'est plus disponible. Un dragon a coupé la ligne
au-dessus des Pyrénées. ]


Avatar
Vincent Lefevre
Dans l'article <ck3g2f$1im$,
Laurent Deniau écrit:

Le cast n'est pas un probleme selon tes propos (c'etait ma premiere
question) et il est biensur essentiel pour fixer le type de index_t.


Le cast en lui-même n'était pas un problème dans ton exemple
(qui n'utilisait pas le préprocesseur), mais qui ne résolvait
pas non plus le problème.

Le choix du unsigned long n'est pas anodin. Il correspond
generalement au plus gros mot processeur (32, 64, 128, ...)


Non, c'est complètement faux! Sur une machine 32 bits, un
unsigned long fait 32 bits, alors qu'un unsigned long long
en fait 64. Tu me diras, on peut caster en uintmax_t (on va
supposer que le compilo supporte cela, et même si ce n'est
pas le cas, je peux me débrouiller). Pour le uintmax_t, c'est
plus discutable concernant l'optimisation (un uintmax_t peut
être plus grand que la taille d'un registre du processeur
dans la pratique et il faut vraiment que le compilo sache
optimiser -- je serais intéressé de savoir si c'est toujours
le cas avec gcc, indépendemment de cet exemple).

Reste ensuite le problème que la taille du décalage GMP_LIMB_BITS
peut être égale à la taille d'un uintmax_t (cas qui se vérifie en
pratique, par exemple sur machine 64 bits). Mais on peut découper
le décalage en deux (GMP_LIMB_BITS - 1 et 1, par exemple), en
espérant que le compilo optimise (faudrait que j'essaie...).

et garantit 32 bits si ce mot est < 32bits. Certe, le cast est
sous-optimal si index_t < 32 bits.


Dans mon code actuel, j'utilise un uint_fast64_t pour index_t (et
il y aurait des cas où un uint_fast128_t serait bien utile...).

Pour info, dans du code futur, j'utiliserais aussi uint_fast32_t,
mais dans tous les cas, je peux supposer que index_t fait au moins
32 bits, vu que je ne compte pas utiliser de machine 16 bits.

D'autre part, unsigned int peut etre 32 bits sur une archi 64 bits
et utiliser unsigned long long pour la definition de index_t serait
une aberration.


Pourquoi?

Ce n'est pas une solution propre. Je n'ai pas envie d'avoir à
retoucher tous mes sources dans 10 ans quand une nouvelle plateforme
apparaîtra (par exemple avec un type sur 512 bits).


Ce type aura peut d'interet (~ 10^154).


Il aurait un très grand intérêt pour moi. J'utilise actuellement
MPN pour faire des calculs sur 256 bits (128 bits devraient suffire
actuellement, cependant, mais il faut que je finalise mon code pour
en être sûr).

Tu as deja regarde ce que vaut 2^128-1 (~ 10^38) ?


Ce qui ne suffit pas pour ce que je veux faire.

Il y a d'autres exemples, comme SCSLib[*], qui fait par défaut ses
calculs internes en 256 bits de précision.

[*] http://www.ens-lyon.fr/LIP/Arenaire/Ware/SCSLib/

J'attends avec impatience ta solution.


Si j'ai posé la question ici, ce n'est pas pour rien.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Vincent Lefevre
Dans l'article <ck3i0s$2r0$,
Antoine Leca écrit:

En 20041007115911$, Vincent Lefevre va escriure:
Dans l'article <ck0fuf$q8h$,
Antoine Leca écrit:

Autrement dit, si le comportement indéfini est dans du code non
évalué, [...]


Mais si le comportement indéfini est dans du code évalué à la
traduction (cf 6.6#2, ce qui est le cas qui me préoccupe)?


Est-il évalué, ou non ?


Il est très probablement évalué à la traduction (c'est une
optimisation).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Antoine Leca
En 20041007141852$, Vincent Lefevre va escriure:
Il est très probablement évalué à la traduction (c'est une
optimisation).


Désolé de ne pas avoir été clair.

Je parlais d'évaluation au sens de la norme.
6.5.15p4: "The first operand is evaluated; there is a sequence point after
its evaluation. The second operand is evaluated *only* if [...]" (c'est moi
qui souligne).

Autrement dit, dans l'expression ternaire, exactement deux sous-expressions
sont _évaluées_, l'autre ne l'est pas.


Antoine

Avatar
Laurent Deniau
Vincent Lefevre wrote:
Dans l'article <ck3g2f$1im$,
Laurent Deniau écrit:


Le cast n'est pas un probleme selon tes propos (c'etait ma premiere
question) et il est biensur essentiel pour fixer le type de index_t.



Le cast en lui-même n'était pas un problème dans ton exemple
(qui n'utilisait pas le préprocesseur), mais qui ne résolvait
pas non plus le problème.


Le choix du unsigned long n'est pas anodin. Il correspond
generalement au plus gros mot processeur (32, 64, 128, ...)



Non, c'est complètement faux! Sur une machine 32 bits, un
unsigned long fait 32 bits, alors qu'un unsigned long long
en fait 64.


Je parle chinois? relis ce que j'ai ecrit stp...

D'autre part, unsigned int peut etre 32 bits sur une archi 64 bits
et utiliser unsigned long long pour la definition de index_t serait
une aberration.



Pourquoi?


Je te retourne la question. Pourquoi utiliser unsigned long long?

Ce n'est pas une solution propre. Je n'ai pas envie d'avoir à
retoucher tous mes sources dans 10 ans quand une nouvelle plateforme
apparaîtra (par exemple avec un type sur 512 bits).




Ce type aura peut d'interet (~ 10^154).



Il aurait un très grand intérêt pour moi. J'utilise actuellement
MPN pour faire des calculs sur 256 bits (128 bits devraient suffire
actuellement, cependant, mais il faut que je finalise mon code pour
en être sûr).


Pas standard, il faut une lib specialisee (GMP?). Il ne faut pas
confondre la taille des variables du language qui ont le plus possible
une realite physique (processeur) et la taille des clefs de cryptage,
qui ont une realite algorithmique.

index_t ne sert-il pas a indexer un tableau?

a+, ld.



Avatar
Vincent Lefevre
Dans l'article <ck3m5s$p4c$,
Antoine Leca écrit:

Je parlais d'évaluation au sens de la norme.
6.5.15p4: "The first operand is evaluated; there is a sequence point
after its evaluation. The second operand is evaluated *only* if
[...]" (c'est moi qui souligne).

Autrement dit, dans l'expression ternaire, exactement deux
sous-expressions sont _évaluées_, l'autre ne l'est pas.


Ça, c'est le cas général à l'exécution. Mais la norme dit que les
expressions constantes peuvent être évaluées à la traduction (6.6),
ce qui est mon cas en particulier.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Richard Delorme
Dans l'article <ck3m5s$p4c$,
Antoine Leca écrit:


Je parlais d'évaluation au sens de la norme.
6.5.15p4: "The first operand is evaluated; there is a sequence point
after its evaluation. The second operand is evaluated *only* if
[...]" (c'est moi qui souligne).



Autrement dit, dans l'expression ternaire, exactement deux
sous-expressions sont _évaluées_, l'autre ne l'est pas.



Ça, c'est le cas général à l'exécution. Mais la norme dit que les
expressions constantes peuvent être évaluées à la traduction (6.6),
ce qui est mon cas en particulier.


Et que dit le verset 11 du 6.6 ? Donc en quoi le fait d'être une
expression constante pose un problème ?

--
Richard


Avatar
Vincent Lefevre
Dans l'article <ck3mmj$gle$,
Laurent Deniau écrit:

Vincent Lefevre wrote:
Dans l'article <ck3g2f$1im$,
Laurent Deniau écrit:
Le choix du unsigned long n'est pas anodin. Il correspond
generalement au plus gros mot processeur (32, 64, 128, ...)


Non, c'est complètement faux! Sur une machine 32 bits, un
unsigned long fait 32 bits, alors qu'un unsigned long long
en fait 64.


Je parle chinois? relis ce que j'ai ecrit stp...


Ah, OK, tu parles des *registres* du processeur (j'aurais préféré le
terme "registre", car le terme "mot" peut désigner vraiment n'importe
quoi -- e.g. sur 68k, un mot fait 16 bits, mais les registres font
32 bits).

D'autre part, unsigned int peut etre 32 bits sur une archi 64 bits
et utiliser unsigned long long pour la definition de index_t serait
une aberration.


Pourquoi?


Je te retourne la question. Pourquoi utiliser unsigned long long?


Pour avoir au moins 64 bits (mais j'utilise plutôt les types de
<stdint.h>). Eh oui, 32 bits, ça peut ne pas être suffisant. D'où
l'idée du type générique.

Il aurait un très grand intérêt pour moi. J'utilise actuellement
MPN pour faire des calculs sur 256 bits (128 bits devraient suffire
actuellement, cependant, mais il faut que je finalise mon code pour
en être sûr).


Pas standard, il faut une lib specialisee (GMP?).


Oui, mais je n'ai pas le choix. S'il y avait un moyen de faire du
256 bits en standard, je l'aurais choisi.

Il ne faut pas confondre la taille des variables du language qui ont
le plus possible une realite physique (processeur) et la taille des
clefs de cryptage, qui ont une realite algorithmique.

index_t ne sert-il pas a indexer un tableau?


C'est ici un entier qui donne une position sur un segment (plus
ou moins une abscisse relative, et qui peut aussi être vu comme
un indice dans un groupe).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Laurent Deniau
Vincent Lefevre wrote:
Je te retourne la question. Pourquoi utiliser unsigned long long?


Pour avoir au moins 64 bits (mais j'utilise plutôt les types de
<stdint.h>). Eh oui, 32 bits, ça peut ne pas être suffisant. D'où
l'idée du type générique.


Tu travailles sur une archi ou tu peux indexer un tableau (ou un
segment) sur 64 bits et ou un long ne fait pas 64 bits?

[...]

index_t ne sert-il pas a indexer un tableau?



C'est ici un entier qui donne une position sur un segment (plus
ou moins une abscisse relative, et qui peut aussi être vu comme
un indice dans un groupe).


Alors je ne comprends pas ton besoin. Si c'est effectivement un offset
dans un segment, ca doit tenir dans un registre, donc dans un long.

a+, ld.


Avatar
Antoine Leca
En 20041007161056$,
Vincent Lefevre va escriure:
Dans l'article <ck3m5s$p4c$,
Antoine Leca écrit:

Je parlais d'évaluation au sens de la norme.
6.5.15p4: "The first operand is evaluated; there is a sequence point
after its evaluation. The second operand is evaluated *only* if
[...]" (c'est moi qui souligne).

Autrement dit, dans l'expression ternaire, exactement deux
sous-expressions sont _évaluées_, l'autre ne l'est pas.


Ça, c'est le cas général à l'exécution.


Euh ?
Où ai-je écrit « exécution » ?

Mais la norme dit que les expressions constantes peuvent être
évaluées à la traduction (6.6),


Et alors ? À la traduction, on va évaluer la première sous-expression, et si
elle est constante (cela vaux mieux) on va ensuite choisir « d'évaluer » (au
sens de la machine virtuelle) l'une ou l'autre des deux autres
sous-expressions. Où est le problème ?

Ce que fait le compilateur de son côté m'est complètement égal. Enfin, pas
complètement: si le compilo plante brutal à cause de ma division par 0 (à
condition de ne avoir #défini O, bien sûr), j'ai une non-conformité.


Antoine