Vincent Lefevre a écrit :
>> http://www.abxsoft.com/misra/misra-test.html
>> /* Rule 50: Required */
>> /* Floating point variables shall not be tested for exact equality or */
>> /* inequality. */
>> MISRA-C [1998:2004] Function Definition: rule50
>
> Il y a des cas où le test d'égalité a un sens. Mais bon...
Sans doute. Mais si tu as des exemples concrets ca m'interresse
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Car en fait quand on utilise les floats/doubles, il y a parfois des
surprises entre ce qu'on croit que le compilo fait, et ce qu'il fait
vraiment.
> Faut bien se dire que de tels "standards de codages industriels"
> ont leur spécificité. À la même URL:
>
> /* Rule 13: Advisory */
> /* The basic types char, short, int, long, float and double should not */
> /* be used. */
Oui le standard est utilisé dans les calculateurs automobiles. Là dedans
tu as des ECU 8bits, 16bits, 32bits et voir plus. Le problème c'est les
types C ne sont pas assez précis concernant le nombre de bits
indépendamment de l'architecture. Le standards recommande donc (cf le
Advisory) d'utiliser les versions indiquant le nombre de bits: uint32,
int8, etc.
Vincent Lefevre a écrit :
>> http://www.abxsoft.com/misra/misra-test.html
>> /* Rule 50: Required */
>> /* Floating point variables shall not be tested for exact equality or */
>> /* inequality. */
>> MISRA-C [1998:2004] Function Definition: rule50
>
> Il y a des cas où le test d'égalité a un sens. Mais bon...
Sans doute. Mais si tu as des exemples concrets ca m'interresse
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Car en fait quand on utilise les floats/doubles, il y a parfois des
surprises entre ce qu'on croit que le compilo fait, et ce qu'il fait
vraiment.
> Faut bien se dire que de tels "standards de codages industriels"
> ont leur spécificité. À la même URL:
>
> /* Rule 13: Advisory */
> /* The basic types char, short, int, long, float and double should not */
> /* be used. */
Oui le standard est utilisé dans les calculateurs automobiles. Là dedans
tu as des ECU 8bits, 16bits, 32bits et voir plus. Le problème c'est les
types C ne sont pas assez précis concernant le nombre de bits
indépendamment de l'architecture. Le standards recommande donc (cf le
Advisory) d'utiliser les versions indiquant le nombre de bits: uint32,
int8, etc.
Vincent Lefevre a écrit :
>> http://www.abxsoft.com/misra/misra-test.html
>> /* Rule 50: Required */
>> /* Floating point variables shall not be tested for exact equality or */
>> /* inequality. */
>> MISRA-C [1998:2004] Function Definition: rule50
>
> Il y a des cas où le test d'égalité a un sens. Mais bon...
Sans doute. Mais si tu as des exemples concrets ca m'interresse
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Car en fait quand on utilise les floats/doubles, il y a parfois des
surprises entre ce qu'on croit que le compilo fait, et ce qu'il fait
vraiment.
> Faut bien se dire que de tels "standards de codages industriels"
> ont leur spécificité. À la même URL:
>
> /* Rule 13: Advisory */
> /* The basic types char, short, int, long, float and double should not */
> /* be used. */
Oui le standard est utilisé dans les calculateurs automobiles. Là dedans
tu as des ECU 8bits, 16bits, 32bits et voir plus. Le problème c'est les
types C ne sont pas assez précis concernant le nombre de bits
indépendamment de l'architecture. Le standards recommande donc (cf le
Advisory) d'utiliser les versions indiquant le nombre de bits: uint32,
int8, etc.
Dans l'article <4bb29128$0$14657$,
Samuel DEVULDER écrit:Cela dit suivant le parseur utilisé on peut avoir des soucis car la
partie "0.5" peut être traduite par un 5*0.1, avec le 0.1 qui n'est pas
exact.
Ce serait un bug.
Beurk. Utiliser %a (ISO C99).Ah? oui peut-être.. mais c'est un détail superflu pour le sujet à mon
avis. D'ailleurs moi je voulais imprimer des *entiers* et pas des
flottants en hexa, donc %a est hors sujet.
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
hexa plus parlante que l'encodage brut: s'il y a une différence entre
deux valeurs, on voit mieux à quoi elle correspond.
Dans l'article <4bb29128$0$14657$426a74cc@news.free.fr>,
Samuel DEVULDER <samuel-dot-devulder@laposte-dot-com> écrit:
Cela dit suivant le parseur utilisé on peut avoir des soucis car la
partie "0.5" peut être traduite par un 5*0.1, avec le 0.1 qui n'est pas
exact.
Ce serait un bug.
Beurk. Utiliser %a (ISO C99).
Ah? oui peut-être.. mais c'est un détail superflu pour le sujet à mon
avis. D'ailleurs moi je voulais imprimer des *entiers* et pas des
flottants en hexa, donc %a est hors sujet.
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
hexa plus parlante que l'encodage brut: s'il y a une différence entre
deux valeurs, on voit mieux à quoi elle correspond.
Dans l'article <4bb29128$0$14657$,
Samuel DEVULDER écrit:Cela dit suivant le parseur utilisé on peut avoir des soucis car la
partie "0.5" peut être traduite par un 5*0.1, avec le 0.1 qui n'est pas
exact.
Ce serait un bug.
Beurk. Utiliser %a (ISO C99).Ah? oui peut-être.. mais c'est un détail superflu pour le sujet à mon
avis. D'ailleurs moi je voulais imprimer des *entiers* et pas des
flottants en hexa, donc %a est hors sujet.
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
hexa plus parlante que l'encodage brut: s'il y a une différence entre
deux valeurs, on voit mieux à quoi elle correspond.
Sans doute. Mais si tu as des exemples concrets ca m'interresse
Le cas classique:
if (x != y)
a = b / (x - y);
else
...
On a aussi x != x pour tester si x est NaN.
Aussi après un appel de rint...
Après, on peut passer dans des algo avancés, où on contrôle l'erreur.
Un exemple dans le code de CRlibm:
if(logh == (logh + (logm * RNROUNDCST)))
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Non! D'une part c'est incorrect, car les représentations ne sont pas
forcément identiques
avec un long double en 80 bits dans une union). D'autre part, ce serait
plus lent.
Des types de <stdint.h> pourraient être utilisés. Mais c'est peut-être
trop nouveau...
Sans doute. Mais si tu as des exemples concrets ca m'interresse
Le cas classique:
if (x != y)
a = b / (x - y);
else
...
On a aussi x != x pour tester si x est NaN.
Aussi après un appel de rint...
Après, on peut passer dans des algo avancés, où on contrôle l'erreur.
Un exemple dans le code de CRlibm:
if(logh == (logh + (logm * RNROUNDCST)))
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Non! D'une part c'est incorrect, car les représentations ne sont pas
forcément identiques
avec un long double en 80 bits dans une union). D'autre part, ce serait
plus lent.
Des types de <stdint.h> pourraient être utilisés. Mais c'est peut-être
trop nouveau...
Sans doute. Mais si tu as des exemples concrets ca m'interresse
Le cas classique:
if (x != y)
a = b / (x - y);
else
...
On a aussi x != x pour tester si x est NaN.
Aussi après un appel de rint...
Après, on peut passer dans des algo avancés, où on contrôle l'erreur.
Un exemple dans le code de CRlibm:
if(logh == (logh + (logm * RNROUNDCST)))
car en fait je me dit que si on veut une équalité stricte, alors il
est plus simple de passer par un union et comparer (bit à bits) les
entiers correspondants.
Non! D'une part c'est incorrect, car les représentations ne sont pas
forcément identiques
avec un long double en 80 bits dans une union). D'autre part, ce serait
plus lent.
Des types de <stdint.h> pourraient être utilisés. Mais c'est peut-être
trop nouveau...
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
Hum? Je ne vois pas. D'un coté tu as 2 long int à 32 bits chacun, et de
l'autre 64bits. Ca doit rentrer.
union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
Hum? Je ne vois pas. D'un coté tu as 2 long int à 32 bits chacun, et de
l'autre 64bits. Ca doit rentrer.
union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
Le code est tout de même faux sur la plupart des machines actuelles
(avec des long sur 64 bits)!
Hum? Je ne vois pas. D'un coté tu as 2 long int à 32 bits chacun, et de
l'autre 64bits. Ca doit rentrer.
union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
Le code est donc:union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
on lui passe un long, c'est non conforme
Le code est donc:
union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
on lui passe un long, c'est non conforme
Le code est donc:union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
on lui passe un long, c'est non conforme
long *ptr = &d;
long *ptr = &d;
long *ptr = &d;
Jean-Marc Bourguet a écrit :Le code est donc:union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
ah? j'aurais dit un float d'après le code.on lui passe un long, c'est non conforme
Où a tu lu qu'on écrit dans x?? Moi je conclue plutôt que ce sont tes
lunettes qui sont non conformes ;-)
Faudrait arrêter de couper les cheveux en 4 à un moment et se concentrer
sur les vrais pbs. J'ai bien précisé dans ma réponse d'origine:
(bon c'est l'idée... )
C'est à dire qu'ici je me fiche des détails qui ne sont pas important pour
l'exemple. J'aurais pu tout aussi justement écrire:
double d = 1.7 + 0.1;
long *ptr = &d;
printf("%08x%08xn" ptr[0], ptr[1]);
d = x + 0.1;
printf("%08x%08xn" ptr[0], ptr[1]);
Ca aurait le même but: un code indicatif, jouet, pour voir en quoi 1.7+0.1
et x+0.1 en mémoire ne sont pas a même chose.
Jean-Marc Bourguet a écrit :
Le code est donc:
union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
ah? j'aurais dit un float d'après le code.
on lui passe un long, c'est non conforme
Où a tu lu qu'on écrit dans x?? Moi je conclue plutôt que ce sont tes
lunettes qui sont non conformes ;-)
Faudrait arrêter de couper les cheveux en 4 à un moment et se concentrer
sur les vrais pbs. J'ai bien précisé dans ma réponse d'origine:
(bon c'est l'idée... )
C'est à dire qu'ici je me fiche des détails qui ne sont pas important pour
l'exemple. J'aurais pu tout aussi justement écrire:
double d = 1.7 + 0.1;
long *ptr = &d;
printf("%08x%08xn" ptr[0], ptr[1]);
d = x + 0.1;
printf("%08x%08xn" ptr[0], ptr[1]);
Ca aurait le même but: un code indicatif, jouet, pour voir en quoi 1.7+0.1
et x+0.1 en mémoire ne sont pas a même chose.
Jean-Marc Bourguet a écrit :Le code est donc:union {long int i[2]; double d;} nb;
nb.d = 1.7 + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
nb.d = x + 0.1;
printf("%08x%08xn", nb.i[0], nb.i[1]);
- x attend un unsigned int
ah? j'aurais dit un float d'après le code.on lui passe un long, c'est non conforme
Où a tu lu qu'on écrit dans x?? Moi je conclue plutôt que ce sont tes
lunettes qui sont non conformes ;-)
Faudrait arrêter de couper les cheveux en 4 à un moment et se concentrer
sur les vrais pbs. J'ai bien précisé dans ma réponse d'origine:
(bon c'est l'idée... )
C'est à dire qu'ici je me fiche des détails qui ne sont pas important pour
l'exemple. J'aurais pu tout aussi justement écrire:
double d = 1.7 + 0.1;
long *ptr = &d;
printf("%08x%08xn" ptr[0], ptr[1]);
d = x + 0.1;
printf("%08x%08xn" ptr[0], ptr[1]);
Ca aurait le même but: un code indicatif, jouet, pour voir en quoi 1.7+0.1
et x+0.1 en mémoire ne sont pas a même chose.
Avec exactement les mêmes problèmes qu'on passe à printf autre chose que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Avec exactement les mêmes problèmes qu'on passe à printf autre chose que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Avec exactement les mêmes problèmes qu'on passe à printf autre chose que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Jean-Marc Bourguet a écrit :Avec exactement les mêmes problèmes qu'on passe à printf autre chose
que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas
décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Oui, tu as raison. On peu supposer beaucoup de choses.. mais vu qu'on en
est à avoir un compilo sous la main (on s'éloigne de l'exemple de code
jouet pour fixer les idée du départ, mais bon), j'en connais qui, en ne
supposant pas grand chose, en optimisant pas vraiment (tcc par exemple),
refusent le code parce qu'il manque une belle virgule avant prt[0].Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Ok, c'est exact. C'est quand même bien plus lourd que les unions du
début. J'ose pas imaginer le code pour recopier les deux valeurs doubles
dans deux fois deux long et faire un xor entre les deux pour afficher
les bits qui ont bougés. Je sens que globalement je préfère le 1er code,
qui s'il n'est pas strictement juste, a le mérite de la simplicité.
En tout cas une chose est sure: à voir les messages, il y a presque plus
à dire autour de l'usage des unions pour afficher des doubles sans
passer par des pointeurs que de comprendre en quoi:
(1.7f + 0.1) != (1.7 + 0.1).
bon allez.. je crois qu'on a fait le tour et qu'on apporte plus rien à
la question d'origine. Tout est dit.
sam (l'union a semée la division apparemment, c'est paradoxal :-) )
Jean-Marc Bourguet a écrit :
Avec exactement les mêmes problèmes qu'on passe à printf autre chose
que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas
décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Oui, tu as raison. On peu supposer beaucoup de choses.. mais vu qu'on en
est à avoir un compilo sous la main (on s'éloigne de l'exemple de code
jouet pour fixer les idée du départ, mais bon), j'en connais qui, en ne
supposant pas grand chose, en optimisant pas vraiment (tcc par exemple),
refusent le code parce qu'il manque une belle virgule avant prt[0].
Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Ok, c'est exact. C'est quand même bien plus lourd que les unions du
début. J'ose pas imaginer le code pour recopier les deux valeurs doubles
dans deux fois deux long et faire un xor entre les deux pour afficher
les bits qui ont bougés. Je sens que globalement je préfère le 1er code,
qui s'il n'est pas strictement juste, a le mérite de la simplicité.
En tout cas une chose est sure: à voir les messages, il y a presque plus
à dire autour de l'usage des unions pour afficher des doubles sans
passer par des pointeurs que de comprendre en quoi:
(1.7f + 0.1) != (1.7 + 0.1).
bon allez.. je crois qu'on a fait le tour et qu'on apporte plus rien à
la question d'origine. Tout est dit.
sam (l'union a semée la division apparemment, c'est paradoxal :-) )
Jean-Marc Bourguet a écrit :Avec exactement les mêmes problèmes qu'on passe à printf autre chose
que ce
qu'on lui indique et qu'on suppose que le compilateur ne va pas
décider des
choses en supposant que d n'est jamais utilisé (ptr est un pointeur vers
long, il ne peut pas aliaser un double).
Oui, tu as raison. On peu supposer beaucoup de choses.. mais vu qu'on en
est à avoir un compilo sous la main (on s'éloigne de l'exemple de code
jouet pour fixer les idée du départ, mais bon), j'en connais qui, en ne
supposant pas grand chose, en optimisant pas vraiment (tcc par exemple),
refusent le code parce qu'il manque une belle virgule avant prt[0].Pour éviter ces problèmes
unsigned char* ptr = (char*)&d;
for (i = 0; i < sizeof(double); ++i)
printf("%02x", ptr[i]);
si on ne dispose pas de %a.
Ok, c'est exact. C'est quand même bien plus lourd que les unions du
début. J'ose pas imaginer le code pour recopier les deux valeurs doubles
dans deux fois deux long et faire un xor entre les deux pour afficher
les bits qui ont bougés. Je sens que globalement je préfère le 1er code,
qui s'il n'est pas strictement juste, a le mérite de la simplicité.
En tout cas une chose est sure: à voir les messages, il y a presque plus
à dire autour de l'usage des unions pour afficher des doubles sans
passer par des pointeurs que de comprendre en quoi:
(1.7f + 0.1) != (1.7 + 0.1).
bon allez.. je crois qu'on a fait le tour et qu'on apporte plus rien à
la question d'origine. Tout est dit.
sam (l'union a semée la division apparemment, c'est paradoxal :-) )
Bonjour,
Si j'ai bien compris %a est le spécificateur format de printf pour
afficher un float en base 16.
Y a-t-il un site où on peut trouver les réponses aux questions suivantes:
Question 1 : pour les doubles c'est %la ?
Question 2 : quelle est la lettre pour l'exposant en hexa
(e comme en décimal?)
Question 3 : y a-t-il un équivalent des notations fixe, scientifique, et
ingénérie (%f, %e et %g)
Question 4 : Comment écrit-on une constante immédiates float en hexa
Est-ce que 0x0.1f est équivalent à 0.0625f, 0x0.1 à
0.0625?
Question 5 : En C++ (pas en C) un ostream de gcc formate -0.0
(0.0 avec un bit de signe = 1) en `-0.0', alors que
VisualC++ le formate en `0.0'. Je ne sais pas ce que fait
printf, mais comment ça devrait être ? Et en général,
est-ce qu'un 0.0 avec un bit de signe à 1 est une valeur
valide ?
Bonjour,
Si j'ai bien compris %a est le spécificateur format de printf pour
afficher un float en base 16.
Y a-t-il un site où on peut trouver les réponses aux questions suivantes:
Question 1 : pour les doubles c'est %la ?
Question 2 : quelle est la lettre pour l'exposant en hexa
(e comme en décimal?)
Question 3 : y a-t-il un équivalent des notations fixe, scientifique, et
ingénérie (%f, %e et %g)
Question 4 : Comment écrit-on une constante immédiates float en hexa
Est-ce que 0x0.1f est équivalent à 0.0625f, 0x0.1 à
0.0625?
Question 5 : En C++ (pas en C) un ostream de gcc formate -0.0
(0.0 avec un bit de signe = 1) en `-0.0', alors que
VisualC++ le formate en `0.0'. Je ne sais pas ce que fait
printf, mais comment ça devrait être ? Et en général,
est-ce qu'un 0.0 avec un bit de signe à 1 est une valeur
valide ?
Bonjour,
Si j'ai bien compris %a est le spécificateur format de printf pour
afficher un float en base 16.
Y a-t-il un site où on peut trouver les réponses aux questions suivantes:
Question 1 : pour les doubles c'est %la ?
Question 2 : quelle est la lettre pour l'exposant en hexa
(e comme en décimal?)
Question 3 : y a-t-il un équivalent des notations fixe, scientifique, et
ingénérie (%f, %e et %g)
Question 4 : Comment écrit-on une constante immédiates float en hexa
Est-ce que 0x0.1f est équivalent à 0.0625f, 0x0.1 à
0.0625?
Question 5 : En C++ (pas en C) un ostream de gcc formate -0.0
(0.0 avec un bit de signe = 1) en `-0.0', alors que
VisualC++ le formate en `0.0'. Je ne sais pas ce que fait
printf, mais comment ça devrait être ? Et en général,
est-ce qu'un 0.0 avec un bit de signe à 1 est une valeur
valide ?