C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Calculs du point de vue de la norme
Goto page 1, 2, 3, 4  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
jul
Guest





PostPosted: Mon May 15, 2006 2:23 pm    Post subject: Calculs du point de vue de la norme Reply with quote



Salut,

Je programme une application qui fait un fort usage des calculs avec
des valeurs décimales (à virgule) avec les types float ou double. Il
ne me semble pas que ces calculs sont pris directement en charge par
le(s) processeur(s). Ma question est donc la suivante : la norme
impose-t-elle l'identité des résultats de calculs entre différents
compilateurs ? Si oui, au moyen de quel(s) critère(s) ?

Je précise pour bien me faire comprendre. Il facile d'exiger qu'un
compilateur calcule de manière correcte sur les entiers (1+1 doit
toujours être égal à 2), ce qui est en soi une garantie
(extérieure) de l'identité des résultats. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi. Il
n'y a pas alors de "résultat juste" (ex. 1/3 n'a pas d'expression
décimale finie juste, même si certaines sont meilleures que
d'autres). Comment sait-on que la manière de calculer et d'arrondir
sera la même sur chaque compilateur ?

Merci pour vos éclaircissements.
Jul.
Back to top
Ploc
Guest





PostPosted: Mon May 15, 2006 2:23 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote



jul wrote:
Quote:
Salut,

Je programme une application qui fait un fort usage des calculs avec
des valeurs décimales (à virgule) avec les types float ou double. Il
ne me semble pas que ces calculs sont pris directement en charge par
le(s) processeur(s). Ma question est donc la suivante : la norme
impose-t-elle l'identité des résultats de calculs entre différents
compilateurs ? Si oui, au moyen de quel(s) critère(s) ?

Je précise pour bien me faire comprendre. Il facile d'exiger qu'un
compilateur calcule de manière correcte sur les entiers (1+1 doit
toujours être égal à 2), ce qui est en soi une garantie
(extérieure) de l'identité des résultats. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi. Il
n'y a pas alors de "résultat juste" (ex. 1/3 n'a pas d'expression
décimale finie juste, même si certaines sont meilleures que
d'autres). Comment sait-on que la manière de calculer et d'arrondir
sera la même sur chaque compilateur ?

Normalement, c'est la norme IEEE 754 (representation des flottants) qui
assure ca, mais rien a voir avec c++.
Back to top
jul
Guest





PostPosted: Mon May 15, 2006 3:23 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote



Merci pour l'info. Ma question est maintenant : cette norme est-elle
généralement suivie par les logiciels/matériels, et en particulier
par C++ ?

Jul.
Back to top
kanze
Guest





PostPosted: Mon May 15, 2006 4:25 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote

jul wrote:

Quote:
Je programme une application qui fait un fort usage des
calculs avec des valeurs décimales (à virgule) avec les types
float ou double.

Tu crois ? Je ne connais pas de machine moderne où les float ou
les double sont des types décimaux. Binaire, la plupart du
temps, ou héxadécimal, mais pas décimaux.

Quote:
Il ne me semble pas que ces calculs sont pris directement en
charge par le(s) processeur(s).

Ça dépend du hardware, mais sur tous les processeurs
généralistes aujourd'hui, les calculs flottants sont implémentés
directement dans l'hardware.

Quote:
Ma question est donc la suivante : la norme impose-t-elle
l'identité des résultats de calculs entre différents
compilateurs ?

Pas du tout. Elle n'impose même pas une identité entre deux
calculs identiques dans le même programme -- ce n'est pas rare
de trouver des cas comme :

double i = 1.0, j = 3.0 ;
double test = i / j ;
assert( test == i / j ) ;

Non seulement le non-échec de l'assert n'est pas garantie par
la norme, il y a des systèmes où il risque fort d'échouer.

Quote:
Si oui, au moyen de quel(s) critère(s) ?

Je précise pour bien me faire comprendre. Il facile d'exiger
qu'un compilateur calcule de manière correcte sur les entiers
(1+1 doit toujours être égal à 2), ce qui est en soi une
garantie (extérieure) de l'identité des résultats. Mais
lorsque le calcul a lieu sur des nombres décimaux, le résultat
est souvent arrondi. Il n'y a pas alors de "résultat juste"
(ex. 1/3 n'a pas d'expression décimale finie juste, même si
certaines sont meilleures que d'autres). Comment sait-on que
la manière de calculer et d'arrondir sera la même sur chaque
compilateur ?

Je comprends bien ton problème. Le réponse, c'est que dans les
faits, la manière de calculer et d'arrondir n'est pas la même
d'un compilateur à l'autre -- elle n'est même pas la même selon
les options du compilateur, ni même entre deux sous-expressions
dans le même programme : dans mon exemple ci-dessus, si
l'expression i / j se trouve dans des expressions plus complexe,
parfois elle aurait la valeur qu'on trouve en test, ci-dessus,
et parfois la valeur qui n'est pas égale à test.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Mon May 15, 2006 4:25 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Ploc wrote:
Quote:
jul wrote:

Je programme une application qui fait un fort usage des
calculs avec des valeurs décimales (à virgule) avec les
types float ou double. Il ne me semble pas que ces calculs
sont pris directement en charge par le(s) processeur(s). Ma
question est donc la suivante : la norme impose-t-elle
l'identité des résultats de calculs entre différents
compilateurs ? Si oui, au moyen de quel(s) critère(s) ?

Je précise pour bien me faire comprendre. Il facile d'exiger
qu'un compilateur calcule de manière correcte sur les
entiers (1+1 doit toujours être égal à 2), ce qui est en soi
une garantie (extérieure) de l'identité des résultats. Mais
lorsque le calcul a lieu sur des nombres décimaux, le
résultat est souvent arrondi. Il n'y a pas alors de
"résultat juste" (ex. 1/3 n'a pas d'expression décimale
finie juste, même si certaines sont meilleures que
d'autres). Comment sait-on que la manière de calculer et
d'arrondir sera la même sur chaque compilateur ?

Normalement, c'est la norme IEEE 754 (representation des
flottants) qui assure ca, mais rien a voir avec c++.

Elle est loin d'être universale, et elle laisse un certain
nombre de libertés à l'implémentation aussi. Donc, des deux
processeurs que j'ai sous la main (un PC sous Linux et un Sun
Sparc sous Solaris), le programme :

#include <assert.h>

int
main()
{
double i = 1.0, j = 3.0 ;
double test = i / j ;
assert( test == i / j ) ;
return 0 ;
}

fait un core dump sur le PC, mais pas sur le Sparc. Bien que
tous les deux utilisent IEEE 754 pour les flottants. (Je crois
qu'il y a une option de g++ pour empècher le core dump. Mais
elle n'est pas active par défaut, et elle rallentit le
processeur pas mal.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Jean-Marc Bourguet
Guest





PostPosted: Mon May 15, 2006 4:25 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote

"jul" <julien_ferard (AT) yahoo (DOT) fr> writes:

Quote:
Je programme une application qui fait un fort usage des calculs avec
des valeurs décimales (à virgule) avec les types float ou double.

Ouille, il y a de la confusion.

Les types decimaux sont des types dont la representation est basee sur
des chiffres decimaux. Si on exclus les problemes de limites, ca ne
change le comportement observable que pour des nombres non entiers.

On a plusieurs types de nombres non entiers. En restant avec des
representations en espace constant, on peut avoir:

- des rationnels ou le numerateur et le denominateur sont
explicitement donnes dans le nombre; c'est relativement rare (Common
Lisp en a)

- des rationnels ou le denominateur est implicite. C'est les nombres
en virgule fixe. Il sont decimaux si le denominateur est une
puissance de 10, binaires si c'est une puissance de 2. Ce genre de
representation a borne constante de l'erreur absolue.

- on represente en virgule fixe le logarithme du nombre. C'est
interessant, on a une borne constante de l'erreur relative. C'est
complique a implementer si on veut pouvoir faire des additions.

- on represente un nombre en deux partie: une partie fractionnaire
(alias mantisse) entre 0 et un en virgule fixe et un exposant (qui
correspond a la partie entiere du logarithme). On a une bonne
approximation d'un systeme avec une borne constante de l'erreur
relative, mais plus simple a implementer qu'une representation
logarithmique. C'est les nombres en virgules flottantes. A
nouveau, binaire si la base est 2, decimal si la base est 10,
hexadecimal si la base est 16. La version binaire est plus proche
de la representation logarithmique et est donc preferee des
numericiens (pour autant que je les ai compris).

float et double sont classiquement des nombres en virgule flottante
binaires.

Quote:
Il ne me semble pas que ces calculs sont pris directement en charge
par le(s) processeur(s).

Les processeurs ont generalement un support pour des entiers (qui est
un cas degenere de la virgule fixe) et des nombres en virgule
flottante binaires.

Quote:
Ma question est donc la suivante : la norme impose-t-elle l'identité
des résultats de calculs entre différents compilateurs ?

Non. Je ne connais pas de langage ou c'est le cas. Java a tente
d'impose le comportement en se referant a IEEE 754 mais est revenu en
arriere au moins dans des cas limites (_denormaux_, gestion des
infinis, _NaN_, ...) pour des raisons de performance. Vouloir
l'identite de resultats sur des calculs en virgule flottante, c'est
serieusement contraindre les implementations.

Quote:
Je précise pour bien me faire comprendre. Il facile d'exiger qu'un
compilateur calcule de manière correcte sur les entiers (1+1 doit
toujours être égal à 2), ce qui est en soi une garantie
(extérieure) de l'identité des résultats. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi. Il
n'y a pas alors de "résultat juste" (ex. 1/3 n'a pas d'expression
décimale finie juste, même si certaines sont meilleures que
d'autres). Comment sait-on que la manière de calculer et d'arrondir
sera la même sur chaque compilateur ?

Vu la prevalance des flottants binaires, 1/10 n'a souvent pas de
representation exacte en flottant.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Back to top
Fabien LE LEZ
Guest





PostPosted: Mon May 15, 2006 5:22 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote

On 15 May 2006 05:28:51 -0700, "jul" <julien_ferard (AT) yahoo (DOT) fr>:

Quote:
la norme
impose-t-elle l'identité des résultats de calculs entre différents
compilateurs ?

Non. Si tu as besoin de calculs fiables, les types double et float
sont à proscrire.

Il existe (je crois) des spécialistes qui savent effectuer des calculs
avec ces types, mais AMHA ils sont rares -- et a priori, nous n'en
faisons pas partie.
Back to top
Sylvain
Guest





PostPosted: Mon May 15, 2006 10:21 pm    Post subject: Re: Calculs du point de vue de la norme Reply with quote

jul wrote on 15/05/2006 14:28:
Quote:

Je programme une application qui fait un fort usage des calculs avec
des valeurs décimales (à virgule) avec les types float ou double.

(à moi-même, le dernier "fil flottant" a été animé...)

Quote:
Il ne me semble pas que ces calculs sont pris directement en charge
par le(s) processeur(s).

si, par l'unité idoine du proc.

(seuls les vieux compilos des vieilles machines dépourvus de "co-proc
arith." (disait-on à l'époque) utilisaient des libs math. d'émulation,
je ne pense pas que vous rencontrerez cela aujourd'hui - sauf peut être
pour du code embarqué.)

Quote:
Ma question est donc la suivante : la norme impose-t-elle
l'identité des résultats de calculs entre différents
compilateurs ? Si oui, au moyen de quel(s) critère(s) ?

la question n'est dès lors plus "entre différents compilateurs" mais
entre différents CPU.
bcp, surement pas tous, utilisent les normes IEEE déjà cités, donc ils
sont censés se comporter à peu près pareil ... pour autant l'identité
n'est pas garantie et _surtout_ ne doit pas être cherchée (un code
numérique ne contient jamais d'opérateur == ...ok sauf pour les boucles)

Quote:
[...] Il facile d'exiger qu'un compilateur calcule de manière
correcte sur les entiers [...]. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi.

toujours même sauf cas particuliers (0, NaN, inf).

Quote:
Comment sait-on que la manière de calculer et d'arrondir
sera la même sur chaque compilateur ?

pour un compilo et/ou un hard utilisant la même représentation (c'est
assez facilement atteint) et le même mode opératoire de calcul (le même
cablage) (ça c'est jamais le cas - chaque fondeur choisit ses propres
tables) la manière de calculer et d'arrondir est identique; mais il
existe des différences (subtiles) dans le hard qui influenceront les
arrondis et le résultat final.

si votre question était donc simplement: peut-on garantir des identités,
la réponse est non, non pour un même programme sur le même CPU, non pour
le même programme sur 2 CPU/compilateurs différents.

si votre question est: peut-on obtenir les "mêmes résultats" entre
différents compilateurs et/ou CPU, la réponse est oui parce qu'on ne
doit pas parler "d'identité" mais simplement de résultat connu à une
précision donnée.

pour l'anecdote, j'ai fait du calcul numérique pdt en gros 8 ans, et les
codes (certain bien conséquent) donnaient le même résultat _à 10^-8
près_ sur Pentium2 / Studio5, PowerPC601 / CodeWarrior, Sun Sparc2 / gcc
et f77.

la difficulté d'un code numérique n'est jamais de chercher une identité
(cela ne doit jamais être fait, bis), mais de coder tout un cycle de
calcul de manière à conserver le maximum de précision (pas de nombres
dénormaux intermédiaires) et de ne pas générer de débordements (la
matrice ((0.000??, 0.000??), (inf, inf)) a mathématiquement un
déterminant de 0, mais informatiquement elle est imprévisible).

selon la nature de votre calcul, vous pourrez vous en tirer avec une
simple évaluation des valeurs limites de toutes les opérations et écrire
l'ensemble de manière adéquate; avec la complexité des expressions, le
langage peut devenir une aide avec par exemple des représentations
symboliques (fraction, matrice, exp. linéaire, ...) qui se simplifient
et/ou se réorganisent.

Sylvain.
Back to top
Ploc
Guest





PostPosted: Tue May 16, 2006 8:25 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

kanze wrote:
Quote:

Elle est loin d'être universale, et elle laisse un certain
nombre de libertés à l'implémentation aussi. Donc, des deux
processeurs que j'ai sous la main (un PC sous Linux et un Sun
Sparc sous Solaris), le programme :

#include <assert.h

int
main()
{
double i = 1.0, j = 3.0 ;
double test = i / j ;
assert( test == i / j ) ;
return 0 ;
}


ah tiens, amusant. Je fais jamais ca (faire un calcul dans un assert),
mais c'est interessant.
Faudra que je regarde ce que donne le code assembleur, parce qu'en
faisant le calcul dans une variable avant, ca fonctionne (j'ai pas dit
portable, malgre ce que je pensais...).
Back to top
kanze
Guest





PostPosted: Tue May 16, 2006 9:21 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Ploc wrote:
Quote:
kanze wrote:

Elle est loin d'être universale, et elle laisse un certain
nombre de libertés à l'implémentation aussi. Donc, des deux
processeurs que j'ai sous la main (un PC sous Linux et un Sun
Sparc sous Solaris), le programme :

#include <assert.h

int
main()
{
double i = 1.0, j = 3.0 ;
double test = i / j ;
assert( test == i / j ) ;
return 0 ;
}

ah tiens, amusant. Je fais jamais ca (faire un calcul dans un
assert), mais c'est interessant.

L'assert n'y est pour rien. Mon point, c'était simplement que
selon l'utilisation qu'on en fait, 1.0/3.0 ne donne pas toujours
le même résultat. La façon la plus simple et la plus sûr d'avoir
un résultat différent, c'est de le mettre dans une variable de
type double dans un cas, et non dans l'autre, dans des
expressions très simples. Dans une expression plus compliquée,
le résultat pourrait dépendre de si le compilateur a pu garder
tous les résultats intermédiaires en régistres, ou s'il a fallu
qu'ils en sauvent certains dans des variables temporaires en
mémoire. Ce qui en son tour pourrait dépendre du niveau
d'optimisation.

Quote:
Faudra que je regarde ce que donne le code assembleur, parce
qu'en faisant le calcul dans une variable avant, ca fonctionne
(j'ai pas dit portable, malgre ce que je pensais...).

Une fois que tu stockes dans une variable nommée, tu es garanti
la précision de la variable pour ce résultat -- ni plus, ni
moins. Mais la norme permet les calculs et les résultats
intermédiaire d'avoir une précision plus grande. Donc, si
j'écris quelque chose du genre :

double i = 1.0, j = 3.0 ;
double test = i / j ;
double t1 = test * 3.1, t2 = i / j * 3.1 ;

t1 et t2 ne sont pas égaux. Ou ils le sont -- ça change selon
les options d'optimisation.

Je ne suis pas spécialiste dans le domaine, mais j'ai comme une
impression que ce genre de chose pourrait rendre l'évaluation de
la stabilité d'un calcul plutôt difficile.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Tue May 16, 2006 9:21 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Fabien LE LEZ wrote:
Quote:
On 15 May 2006 05:28:51 -0700, "jul" <julien_ferard (AT) yahoo (DOT) fr>:

la norme
impose-t-elle l'identité des résultats de calculs entre
différents compilateurs ?

Non. Si tu as besoin de calculs fiables, les types double et
float sont à proscrire.

Il existe (je crois) des spécialistes qui savent effectuer des
calculs avec ces types, mais AMHA ils sont rares -- et a
priori, nous n'en faisons pas partie.

Pour quels nous ? En ce qui me concerne, tu as certainement
raison -- je te fais confiance pour ton évaluation de toi-même
aussi. Mais d'après ce que j'ai compris, je crois que Gaby
saurait le faire, et je crois que Jean-Marc, s'il s'y mettait,
aussi.

Ce que je crois qu'on pourrait dire, c'est que même quand il
s'agit d'un spécialiste, qui sait le faire, il faut qu'il
reflechisse. Avoir un résultat fiable ne va jamais de soi.

Dans le cas général. Je me sers volentiers des flottants pour
l'affichage d'un percentage, par exemple. Avec au maximum trois
ou quatre chiffres de précision. Si x et y sont des entiers (int
ou long, par exemple), j'ai une assez grande confiance que
l'expression 100.0 * x / y me donnerait un résultat assez fiable
pour un affichage à quatre chiffres. (Mais c'est à peu près ma
limite.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Tue May 16, 2006 9:22 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Jean-Marc Bourguet wrote:

Quote:
float et double sont classiquement des nombres en virgule flottante
binaires.

Juste un détail, mais tu n'as pas dû lire les classiques. Sur
l'IBM 1401, ils étaient base 10 (et pour être classique, c'est
une classique), et sur l'architecture la plus « classique »
encore répandue aujourd'hui, ils sont base 16. Ce n'est que sur
les ordinateurs ultra-moderne et avant garde, dont la conception
de l'architecture rémonte à moins de quarante ans, où on peut
être sûr de trouver le binaire.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Jean-Marc Bourguet
Guest





PostPosted: Tue May 16, 2006 10:22 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Sylvain <noSpam (AT) mail (DOT) net> writes:

Quote:
la question n'est dès lors plus "entre différents compilateurs" mais
entre différents CPU. bcp, surement pas tous, utilisent les normes
IEEE déjà cités,

Ils utilisent le format d'IEEE-754, mais prennent plus de libertes
quant au comportement demande. Ces libertes concernent surtout les
denormaux mais ca ne m'etonnerait pas que la precision sur une racine
carree par exemple ne soit pas celle que la norme specifie.

Quote:
donc ils sont censés se comporter à peu près pareil ... pour autant
l'identité n'est pas garantie et _surtout_ ne doit pas être cherchée
(un code numérique ne contient jamais d'opérateur == ...ok sauf pour
les boucles)

C'est une maniere de simplifier le probleme.

Quote:
[...] Il facile d'exiger qu'un compilateur calcule de manière correcte
sur les entiers [...]. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi.

toujours même sauf cas particuliers (0, NaN, inf).

Il y a un peu plus de cas particuliers que cela.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Back to top
Jean-Marc Bourguet
Guest





PostPosted: Tue May 16, 2006 10:22 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

"kanze" <kanze@gabi-soft.fr> writes:

Quote:
Jean-Marc Bourguet wrote:

float et double sont classiquement des nombres en virgule flottante
binaires.

Juste un détail, mais tu n'as pas dû lire les classiques. Sur
l'IBM 1401, ils étaient base 10 (et pour être classique, c'est
une classique), et sur l'architecture la plus « classique »
encore répandue aujourd'hui, ils sont base 16. Ce n'est que sur
les ordinateurs ultra-moderne et avant garde, dont la conception
de l'architecture rémonte à moins de quarante ans, où on peut
être sûr de trouver le binaire.

J'ai dit float et double, en parlant des types C++. Tu as vu une
implementation de C++ ou float et double n'etaient pas binaires?


Quant a l'histoire, si j'ai bien compris, a cette epoque les machines
etaient decimales ou binaires; celles destinees aux charges
"commerciales" -- remplacement des tabulatrices -- decimales, celles
destinees aux charges "scientifiques" -- calculs -- binaires. Donc
j'ai l'impression que les flottants dans leur domaine d'utilisation
naturel sont classiquement binaires. Ce qui ne veut pas dire qu'il
n'y a pas eu une machine ou deux decimales destinnees au calcul
scientifique, ni qu'il n'y a pas eu de machines commerciales binaires,
ni qu'on a jamais fait de calcul sur des machines commerciales.

(Question implementation, d'apres ce que j'ai lu, il y avait souvent
une base binaire soujacente au comportement architectural decimal).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Back to top
kanze
Guest





PostPosted: Tue May 16, 2006 10:22 am    Post subject: Re: Calculs du point de vue de la norme Reply with quote

Sylvain wrote:
Quote:
jul wrote on 15/05/2006 14:28:

[...]
Quote:
Ma question est donc la suivante : la norme impose-t-elle
l'identité des résultats de calculs entre différents
compilateurs ? Si oui, au moyen de quel(s) critère(s) ?

la question n'est dès lors plus "entre différents compilateurs" mais
entre différents CPU.

Pas tout à fait (ou plutôt, la question est beaucoup plus
complexe que ça).

Quote:
bcp, surement pas tous, utilisent les normes IEEE déjà cités,
donc ils sont censés se comporter à peu près pareil ...

La norme IEEE concerne surtout la représentation en mémoire.

Ce qui est important ici, c'est que la norme C++ n'impose pas
une précision fixe au compilateur. Surtout, il permet que les
calculs et les résultats intermédiaires aient une précision plus
grand que celle du type -- sur un processeur Intel, il est
courant que tous les calculs et les résultats intermédiaire dans
les régistres sont systèmatiquement des long double (avec sur
Intel, une précision de 64 bits, plutôt que les 52 d'un double).

Le résultat, c'est que les résultats diffèrent selon que le
compilateur a réussi à garder les résultats intermédiaires en
régistre ou non, ou selon qu'il a trouvé une sous-expression
déjà calculée qu'il réutilise. C-à-d que tu peux avoir deux
résultats différents avec le même compilateur, sur le même CPU,
selon le niveau d'optimisation, et pour une sous expression, où
se trouve la sous-expression dans l'expression complète.

Quote:
pour autant l'identité n'est pas garantie

Sauf quand c'est garantie. Il faut savoir ce qu'on fait.

Quote:
et _surtout_ ne doit pas être cherchée (un code numérique ne
contient jamais d'opérateur == ...ok sauf pour les boucles)

Ça dépend de ce qu'on fait.

Quote:
[...] Il facile d'exiger qu'un compilateur calcule de manière
correcte sur les entiers [...]. Mais lorsque le calcul a
lieu sur des nombres décimaux, le résultat est souvent arrondi.

toujours même sauf cas particuliers (0, NaN, inf).

Sur les nombres décimaux, qui sait. Disons que dans la
comptabilité, il y a des règles qu'il faut suivre.

Mais je crois que par nombres décimaux, le posteur original
voulait dire plutôt les nombres flottants de la machine. La,
parfois, les arrondis dépendent de la niveau d'optimisation du
compilateur, et où l'expression se trouve dans une expression
plus grande ou dans le code. Considérons pour un instant le
programme assez simple :

#include <iostream>
#include <ostream>

int
main()
{
double i = 1.0, j = 3.0 ;
double test = i / j ;
double t1 = test * 3.1, t2 = i / j * 3.1 ;
if ( i / j > 1.0 / 3.0 ) {
std::cout << "x" << std::endl ;
} else {
std::cout << "y" << std::endl ;
}
return 0 ;
}

Sur ma machine Linux, compilé avec « g++ doubleprec.cc », il
affiche "x" ; compilé avec « g++ -O3 doubleprec.cc », il affiche
"y".

Voilà pour le « toujours même ». (Et tu rémarqueras que j'ai
pris soin d'éviter des comparaisons d'égalité.)

Quote:
Comment sait-on que la manière de calculer et d'arrondir
sera la même sur chaque compilateur ?

pour un compilo et/ou un hard utilisant la même représentation
(c'est assez facilement atteint) et le même mode opératoire de
calcul (le même cablage) (ça c'est jamais le cas - chaque
fondeur choisit ses propres tables) la manière de calculer et
d'arrondir est identique; mais il existe des différences
(subtiles) dans le hard qui influenceront les arrondis et le
résultat final.

Si on se limite à IEEE...

Il existe des règles d'arrondi, que la plupart, sinon tous les
hardware respectent. Dans certains cas:-). Certains compilateurs
ont des options pour imposer une variante très stricte, ou
chaque résultat intermédiare est forcé à la précision d'un
double (ni plus, ni moins). Du coup, les résultats sont bien
réproduceables. Mais le calcul est beaucoup plus lent.

Quote:
si votre question était donc simplement: peut-on garantir des
identités, la réponse est non, non pour un même programme sur
le même CPU, non pour le même programme sur 2 CPU/compilateurs
différents.

si votre question est: peut-on obtenir les "mêmes résultats"
entre différents compilateurs et/ou CPU, la réponse est oui
parce qu'on ne doit pas parler "d'identité" mais simplement de
résultat connu à une précision donnée.

Le problème, c'est que c'est faux, même sur un processeur donné,
avec un compilateur donné.

Quote:
la difficulté d'un code numérique n'est jamais de chercher une
identité

Attention : c'est vrai dans beaucoup de cas, surtout quand on ne
considère que ce qu'on appelle habituellement le numérique. Mais
dans des conditions bien contrôlées, si on sait ce qu'on fait,
c'est possible à utiliser les comparaisons pour équalité aussi.
Et les éviter n'est pas une garantie non plus -- voir mon
exemple ci-dessus.

Quote:
(cela ne doit jamais être fait, bis), mais de coder tout un cycle de
calcul de manière à conserver le maximum de précision

Ce qui exige déjà une certaine compréhension des choses.

Il y a eu une discussion ici il y a un certain temps, a propos
de faire une somme des valeurs dans un tableau. J'ai
collectionné les solutions proposée ; on les trouverait (dans le
forme d'un benchmark, mais j'y ai ajouté des tests de précision)
à http://kanze.james.neuf.fr/code/Benchmarks/FloatingPointSum/.
(Note que c'est quelque chose que j'ai fait plutôt pour
moi-même. La présentation n'est donc pas terrible.) C'est
intéressant à noter les différences selon l'algorithme (sur un
Sun Sparc -- sur un Intel, je n'en constate pas avec le jeu de
données par défaut, probablement parce que le compilateur
réussit à garder tout en régistre, avec la précision
supplémentaire). Et que l'algorithme le plus rapide (et le plus
simple et le plus intuitif), c'est celui qui donne toujours le
plus d'erreurs.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Goto page 1, 2, 3, 4  Next
Page 1 of 4

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.