Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

gcc et norme IEEE 754 (IEC 60559)

16 réponses
Avatar
Vincent Lefevre
Il est bien connu que la norme IEEE 754 n'est pas forcément supportée
en C, mais si __STDC_IEC_559__ est défini, on doit s'attendre à un
certain nombre de choses:

Annex F
(normative)


IEC 60559 floating-point arithmetic
[...]
60559 operation, IEC 60559 format, etc. An implementation
that defines __STDC_IEC_559__ shall conform to the |
specifications in this annex. Where a binding between the C
language and IEC 60559 is indicated, the IEC 60559-specified
behavior is adopted by reference, unless stated otherwise.

F.2 Types

[#1] The C floating types match the IEC 60559 formats as
follows:

-- The float type matches the IEC 60559 single format.

-- The double type matches the IEC 60559 double format.
[...]

F.3 Operators and functions

[#1] C operators and functions provide IEC 60559 required
and recommended facilities as listed below.

-- The +, -, *, and / operators provide the IEC 60559 add,
subtract, multiply, and divide operations.
[...]


Maintenant, qu'en est-il avec gcc? Considérons le programme suivant:

#include <stdio.h>

int main(void)
{
volatile double x, y, z;

#ifdef __STDC_IEC_559__
printf("__STDC_IEC_559__ defined\n");
#endif

x = 9007199254740994.0; /* 2^53 + 2 */
y = 1.0 - 1/65536.0;
z = x + y;
printf("z = %.17g\n", z);
return 0;
}

Et voici ce que ça donne avec gcc sous Linux/x86:

__STDC_IEC_559__ defined
z = 9007199254740996

alors qu'on aurait dû obtenir 9007199254740994 conformément à la norme
IEEE 754. Sur x86, gcc définit abusivement __STDC_IEC_559__, non?

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

10 réponses

1 2
Avatar
Éric Lévénez
Le 6/08/03 18:21, dans <20030806161256$, « Vincent Lefevre »
<vincent+ a écrit :

Et voici ce que ça donne avec gcc sous Linux/x86:

__STDC_IEC_559__ defined
z = 9007199254740996

alors qu'on aurait dû obtenir 9007199254740994 conformément à la norme
IEEE 754. Sur x86, gcc définit abusivement __STDC_IEC_559__, non?


Gcc sous Mac OS X/G4 donne :

z = 9007199254740994

Mais __STDC_IEC_559__ n'est pas défini.

--
Éric Lévénez -- <http://www.levenez.com>
Unix is not only an OS, it's a way of life.

Avatar
Erwan David
"Antoine Leca" écrivait :

Ce qui est intéressant, c'est que le comportement par défaut du FPU
(arrondit par défaut au plus proche, les calculs intermédiaires sont
fait avec 64 bits de précision) donne 9007199254740996, ce qui
me semble correct après reflexion (résultat "complet" avant arrondi
9007199254740995, donc exactement au milieu; le - 1p-16 n'a
aucun effet, il est en-dessous de la précision, il faudrait 69|70 bits).
D'où la question plus haut...


Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères
différences. (et a conduit Sun à introduire l'attribut strictfp pour
le VM Java)...

--
Monde de merde

Avatar
Antoine Leca
Erwan David écrivit:
"Antoine Leca" écrivait :

Ce qui est intéressant, c'est que le comportement par défaut du FPU
(arrondit par défaut au plus proche, les calculs intermédiaires sont
fait avec 64 bits de précision) donne 9007199254740996, ce qui
me semble correct après reflexion (résultat "complet" avant arrondi
9007199254740995, donc exactement au milieu; le - 1p-16 n'a
aucun effet, il est en-dessous de la précision, il faudrait 69|70
bits). D'où la question plus haut...


Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères


(64 bits de mantisse)

différences. (et a conduit Sun à introduire l'attribut strictfp pour
le VM Java)...


J'y ai pensé aussi, et pour tout dire j'ai passé une bonne heure à
décompiler différentes versions avec différents compilateurs et
différentes options de contrôle du FPU (tu peux forcer le FPU à
travailler en 53 bits, voire en 24).

Bon je dérive. Ici, cela ne joue pas. On fait l'opération x+1 (on fait
x+y, mais y "vaut" 1 une fois qu'il est mis à l'échelle). Si tu es sur
un x87 "normal", le résultat va être stocké sur 80 bits; ensuite, tu
stocke dans z (par FSTP/fstpl), qui est un double, donc mantisse
sur 53 bits, donc opération d'arrondi. Dans l'autre cas, le calcul
x+1 est fait "directement" en 53 bits, donc il y a arrondi tout de
suite. Le résultat est exactement le même (on aurait une différence
que si on lançait d'autres calculs en même temps).


Antoine


Avatar
Vincent Lefevre
Dans l'article <bh7o6g$efb$,
Antoine Leca écrit:

Vincent Lefevre écrivit:
Il est bien connu que la norme IEEE 754 n'est pas forcément supportée
en C, mais si __STDC_IEC_559__ est défini, on doit s'attendre à un
certain nombre de choses:
[couic]

-- The +, -, *, and / operators provide the IEC 60559 add,
subtract, multiply, and divide operations.


Rafraîchis moi la mémoire S.T.P.: quel mode d'arrondi doit suivre
l'addition en IEC 60559 ? (vers zéro comme en C pour la division,
ou au plus proche ?)


La norme définit 4 modes d'arrondi: au plus près avec arrondi vers
mantisse paire quand on est au milieu, vers -oo, vers +oo et vers 0.
Par défaut, il s'agit de l'arrondi au plus près (avec règle de
l'arrondi pair). Le résultat renvoyé doit être l'arrondi du résultat
*exact* (on parle d'arrondi exact).

Et voici ce que ça donne avec gcc sous Linux/x86:

__STDC_IEC_559__ defined
z = 9007199254740996

alors qu'on aurait dû obtenir 9007199254740994 conformément à la norme
IEEE 754. Sur x86, gcc définit abusivement __STDC_IEC_559__, non?


À tout le moins, cela relève au moins autant de glibc que de gcc
(et probablement beaucoup beaucoup plus).


C'est la glibc qui gère les 4 opérations flottantes +, -, *, / ?

Ce qui est intéressant, c'est que le comportement par défaut du FPU
(arrondit par défaut au plus proche, les calculs intermédiaires sont
fait avec 64 bits de précision) donne 9007199254740996, ce qui
me semble correct après reflexion (résultat "complet" avant arrondi
9007199254740995, donc exactement au milieu; le - 1p-16 n'a
aucun effet, il est en-dessous de la précision, il faudrait 69|70 bits).


Le résultat exact est un peu en-dessous de 9007199254740995. Donc en
double précision, le résultat renvoyé (avec arrondi exact, requis par
la norme IEEE 754) en arrondi au plus près doit être 9007199254740994
et non 9007199254740996. D'où le problème.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Vincent Lefevre
Dans l'article ,
Erwan David écrit:

Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères
différences.


Mais ceci est interdit par la norme IEEE 754. Donc ma remarque sur
la définition de __STDC_IEC_559__.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Antoine Leca
Vincent Lefevre écrivit:
Dans l'article ,
Erwan David écrit:

Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères
différences.


Mais ceci est interdit par la norme IEEE 754. D'où ma remarque sur
la définition de __STDC_IEC_559__.


Ouh là... Vu le poids d'Intel, et l'importance qu'a prise IEEE 754, le
« interdit » ci-dessus est fort (se priver de >90% du marché, pour
une norme, ce n'est pas un jeu auquel on se lance à la légère, il faut
des billes...)

Donc où peut-on lire un argumentaire (avec thèse et anti-thèse) qui
justifie cette interdiction ? (vu qu'à ma connaissance le texte
de 754 ou 854 n'est pas en libre circulation)

NB : je n'ai pas lu IEEE 754, mais je suis surpris que glibc ne suive
pas une norme.


Antoine


Avatar
Antoine Leca
Vincent Lefevre écrivit:
Non, pas toujours le même, car dans le premier cas il y a double
arrondi, et dans certains cas (mon exemple était construit pour),
il y a une différence.


D'accord pour le double arrondi (et oui, cela peut amener une
différence), mais là j'ai pas vu en quoi ton exemple invoquait une
quelconque différence.
J'ai loupé quelque chose, ou c'est toi qui a loupé quelque chose avec
ton 65536.0 qu'il faudrait remplacer par un 1024.0, et là oui il y a
un pépin si Linux te donne 9007199254740994 au lieu du
« correct » 9007199254740996 (si on te suit au sujet de l'obligation
de faire les calculs intermédiaires en 53 bits.)

D'autre part peux-tu m'expliquer

F.7.3 Execution

[#1] At program startup the floating-point environment is
initialized as prescribed by IEC 60559:
[couic]
-- The dynamic rounding precision mode (if supported) is
set so that results are not shortened.

Est-ce que par hasard le mode de précision dynamique a un rapport,
même lointain, avec le contrôle de précision du x87?

Et à propos, que vaut sizeof(double_t) ? 8 (=> calculs en 53 bits), ou
10/12/16 (=> calculs en 64 bits) ?


Antoine

Avatar
Vincent Lefevre
Dans l'article <bh86qp$bs9$,
Antoine Leca écrit:

Vincent Lefevre écrivit:
Dans l'article ,
Erwan David écrit:

Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères
différences.


Mais ceci est interdit par la norme IEEE 754. D'où ma remarque sur
la définition de __STDC_IEC_559__.


Ouh là... Vu le poids d'Intel, et l'importance qu'a prise IEEE 754, le
« interdit » ci-dessus est fort (se priver de >90% du marché, pour
une norme, ce n'est pas un jeu auquel on se lance à la légère, il faut
des billes...)


Du point de vue du processeur, ce n'est pas interdit (la norme IEEE 754
prévoit des calculs en précision étendue). Mais la norme C requiert que
le type double corresponde à de la double précision (non étendue)... si
__STDC_IEC_559__ est défini.

Donc où peut-on lire un argumentaire (avec thèse et anti-thèse) qui
justifie cette interdiction ? (vu qu'à ma connaissance le texte
de 754 ou 854 n'est pas en libre circulation)


Norme C:

-- The double type matches the IEC 60559 double format.

-- The +, -, *, and / operators provide the IEC 60559 add,
subtract, multiply, and divide operations.

donc arrondi exact en double précision (la destination est un double).

Pour la norme IEE 754, tu peux voir ici:

http://www.validlab.com/754R/

les premiers liens. Ça a l'air d'être la norme + des corrections non
techniques (e.g. typos). Cf la section 4.3 notamment. Noter qu'Intel
respecte cette section en autorisant l'arrondi en double ou lieu de
la double étendue. Ensuite, c'est au compilateur d'utiliser cette
fonctionnalité vu ce qu'impose la norme C.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

Vincent Lefevre écrivit:
Dans l'article ,
Erwan David écrit:

Il me semble que par défaut sur pentium les calculs intermédiaires
sont à arrondis à 80 bits, ce qui peut expliquer de légères
différences.


Mais ceci est interdit par la norme IEEE 754. D'où ma remarque sur
la définition de __STDC_IEC_559__.


Ouh là... Vu le poids d'Intel, et l'importance qu'a prise IEEE 754,
le « interdit » ci-dessus est fort (se priver de >90% du marché,
pour une norme, ce n'est pas un jeu auquel on se lance à la légère,
il faut des billes...)


Si j'ai bonne memoire, faire de l'IEEE 754 strict sur ia32, c'est pas
facile. Outre le controle d'arrondi qu'il faut mettre mettre
correctement (en particulier fixer le nombre de chiffres), on est
quand meme oblige de faire des tests en plus parce que l'exposant n'a
pas le bon intervalle et donc que ca pose des problemes pour les
denormaux. Gaby peut vraissemblablement donner plus de details, mais
je pense que -ffloat-store est un minimum a ajouter dans les options
de compilation.

Donc où peut-on lire un argumentaire (avec thèse et anti-thèse) qui
justifie cette interdiction ? (vu qu'à ma connaissance le texte
de 754 ou 854 n'est pas en libre circulation)


Si t'as acces au site de l'IEEE, ca s'y trouve (un pdf sortant d'un
scanner). La norme demande un calcul "comme si" en precision infinie
suivi de l'arrondi choisi par l'utilisateur.

NB : je n'ai pas lu IEEE 754, mais je suis surpris que glibc ne
suive pas une norme.


Ce n'est peut-etre pas uniquement de son ressort.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Vincent Lefevre
Dans l'article ,
Jean-Marc Bourguet écrit:

Si j'ai bonne memoire, faire de l'IEEE 754 strict sur ia32, c'est pas
facile. Outre le controle d'arrondi qu'il faut mettre mettre
correctement (en particulier fixer le nombre de chiffres), on est
quand meme oblige de faire des tests en plus parce que l'exposant n'a
pas le bon intervalle et donc que ca pose des problemes pour les
denormaux. Gaby peut vraissemblablement donner plus de details, mais
je pense que -ffloat-store est un minimum a ajouter dans les options
de compilation.


Tout à fait, mais même sans norme IEEE 754, il s'agit également d'un
bug du compilo, dont on a déjà parlé, quand on stocke le résultat
dans une variable ou que l'on fait un cast.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

1 2