JAVA ne sait pas faire d'addition

Philou1789

Membre actif
12 Juillet 2004
436
30
48
Dans le 77, limite 94
Au secours, je fais des additions en Java avec des doubles et il n'y arrive pas:
HELP

Mon code
double A = 84.4;
double B = 53.2;
double C = A + B;
System.out.println("Tot="+C);
Le resultat:
Tot=137.60000000000002



J'AI JAMAIS VU CA !!!!:confused::confused:
 
Pire regardez moi ca
double A = 84.4;
double B = 53.2;
double C = A + B;
if (C==137.60000000000002)
System.out.println("Tot 1="+C);
else
System.out.println("Tot 2="+C);


Et voilà la réponse:
Tot 1=137.60000000000002


AU SECOURS
 
Curieux :siffle:

Encore pire quand je retire 137....

Bloc de code:
class test
{
        public static void main(String args[])
        {
        double A = 84.4;
        double B = 53.2;
        double C = A + B;
        C = C - 137.0;
        System.out.println("Tot="+C);
        }
}

Bloc de code:
ben-iMac:~/Desktop ben$ java test
Tot=0.6000000000000227

Cela s'explique par la représentation en base 2. Il y a forcément une erreur d'arrondi.
 
c'est la cata, et plus je cherche pire c'est

float R = (float)-84.4;
float T = (float)-53.2;
float I = (float)3116.46;
float P = R + T + I;
System.out.println("Tot 2="+P);

Resultat:
Tot 2=2978.8599

FANTASTIQUE
 
Entre deux nombres réels, il y en a une infinité (contrairement à ce qui se passe avec les entiers);

En informatique, on a un nombre fini de représentations de nombres : plus en double qu'en simple, mais de toutes façons en nombre fini.

Conclusion, les nombres réels ne sont pas représentés exactement par les nombres réels informatiques : on a des erreurs d'arrondi en général. En simple, on a en gros 7 chiffres significatifs corrects, en double plus ou moins le double mais de toutes façons, on n'a pas la valeur exacte.

La représentation des nombres est construite à partir de la base 2 et non de la base 10, ce qui rend le phénomène juste un peu plus visible parce que l'arrondi ne se fait pas sur les puissances de 10 mais sur les puissances de 2.

Java n'est donc pas en cause, tu aurais le même genre de problème en C, en Fortran, en Pascal et tu as la même chose sur les calculatrices, etc. (sauf à utiliser des représentations très spécifiques qui permettent, non pas une précision infinie, mais du moins une précision aussi grande que ce que l'on veut).

Il faut apprendre à le gérer : par exemple, ne pas faire de test du genre " si le réel x est égal à 0.0" mais plutôt des tests du genre "si le réel x est inférieur à epsilon"
 
  • J’aime
Réactions: GrandGibus
Comme Luc G l'explique si bien (et comme je l'évoque plus haut en edit :p), il y a forcément une erreur d'arrondi. Du fait de représentation en base 2, il n'y a donc aucune raison qu'un arrondi se fasse dans ce cas-ci, qui est bien le cas.


Bloc de code:
class test
{
        public static void main(String args[])
        {
        double A = new Double("256.16");
        double B = new Double("16.4");
        double C = (double)A + (double)B;
        System.out.println(A +" + "+ B +" = "+C);
        }
}
 
BeNBiBiFoKe a dit:
Bloc de code:
class test
{
        public static void main(String args[])
        {
        double A = new Double("256.16");
        double B = new Double("16.4");
        double C = (double)A + (double)B;
        System.out.println(A +" + "+ B +" = "+C);
        }
}

Marche pas ca chez moi
 
Philou1789 a dit:
Soit mais au finish, comment on s'en sort ? que propose tu ?

d'adapter ses besoins et les possibilités de l'informatique.

Il y a quelques cas dans la vie courante où on a besoins de plus de 6 chiffres significatifs, pas beaucoup où on a besoin de plus de 12 (c'est à dire de mieux que des doubles). Ensuite, c'est souvent un simple problème d'affichage : si tu affiches ton "137" avec 3 décimales, il n'y a plus d'erreur visible, si tu forces l'arrondi à la troisième décimale, tu vas même un peu plus loin que le visible.

Dans les cas où les 12 chiffres ne suffisent pas, soit il faut utiliser des représentation encore plus fines (genre des réels sur 12 ou 16 octets), soit il faut choisir des algorithmes où ces erreurs d'arrondi posent peu de problèmes.

Par exemple, quand il s'agit de résoudre des systèmes d'équations, donc couramment d'inverser des matrices, certaines méthodes (genre pivot) bloquent dès qu'on augmente la taille de la matrice (je me souviens avoir utilisé sous mac os 6 :D des réels en "extended" qui me permettaient de faire des approximations polynômiales de degré 12 ou 14 plutôt que 8 ou 10, ce qui suffisait dans le cas qui m'intéressait. S'il avait fallu aller au-delà, vu qu'il n'y avait pas (au moins de façon simple) de représentations adéquates, il aurait fallu changer d'algorithmes, passer par des procédures itératives plus lentes mais où ces problèmes se posent moins. C'est entre autres pour cette raison qu'ont été développés des tas d'algorithmes numériques de type itératif moins sensibles à ces problèmes.

Ce qui est assez "amusant", c'est que les problèmes de précision peuvent être vicieux, les bougres. Exemple typique (celui qui d'ailleurs pose problème pour l'inversion de matrices) quand tu dois manipuler des nombres très différents entre eux, exemple tu soustrais 1.0 de 1.0 e15, forcément, ta soustraction ne fait rien même si tes deux nombres ont l'air très simple : 1 dans les 2 cas mais avec une échelle complètement différente. Il faut donc se débrouiller pour éviter d'avoir des calculs de ce type.
 
Luc G a dit:
d'adapter ses besoins et les possibilités de l'informatique.

Il y a quelques cas dans la vie courante où on a besoins de plus de 6 chiffres significatifs, pas beaucoup où on a besoin de plus de 12 (c'est à dire de mieux que des doubles). Ensuite, c'est souvent un simple problème d'affichage : si tu affiches ton "137" avec 3 décimales, il n'y a plus d'erreur visible, si tu forces l'arrondi à la troisième décimale, tu vas même un peu plus loin que le visible.

Dans les cas où les 12 chiffres ne suffisent pas, soit il faut utiliser des représentation encore plus fines (genre des réels sur 12 ou 16 octets), soit il faut choisir des algorithmes où ces erreurs d'arrondi posent peu de problèmes.

Par exemple, quand il s'agit de résoudre des systèmes d'équations, donc couramment d'inverser des matrices, certaines méthodes (genre pivot) bloquent dès qu'on augmente la taille de la matrice (je me souviens avoir utilisé sous mac os 6 :D des réels en "extended" qui me permettaient de faire des approximations polynômiales de degré 12 ou 14 plutôt que 8 ou 10, ce qui suffisait dans le cas qui m'intéressait. S'il avait fallu aller au-delà, vu qu'il n'y avait pas (au moins de façon simple) de représentations adéquates, il aurait fallu changer d'algorithmes, passer par des procédures itératives plus lentes mais où ces problèmes se posent moins. C'est entre autres pour cette raison qu'ont été développés des tas d'algorithmes numériques de type itératif moins sensibles à ces problèmes.

Ce qui est assez "amusant", c'est que les problèmes de précision peuvent être vicieux, les bougres. Exemple typique (celui qui d'ailleurs pose problème pour l'inversion de matrices) quand tu dois manipuler des nombres très différents entre eux, exemple tu soustrais 1.0 de 1.0 e15, forcément, ta soustraction ne fait rien même si tes deux nombres ont l'air très simple : 1 dans les 2 cas mais avec une échelle complètement différente. Il faut donc se débrouiller pour éviter d'avoir des calculs de ce type.


Et merde....il est partit en suçette !:D et Luc G, réveilles-toi :D !








:up:
 
BeNBiBiFoKe a dit:
Et merde....il est partit en suçette !:D et Luc G, réveilles-toi :D !

:D Dès qu'on parle d'arrondi, d'approximation et de toute cette sorte de choses, je me laisse aller, j'ai un brin baigné là-dedans et je rencontre encore dans mon boulot (bien que j'ai laissé les maths de côté il y a un certain temps) les problèmes vicieux dont je cause. C'est du vécu ! :D
 
Luc G a dit:
d'adapter ses besoins et les possibilités de l'informatique.

Il y a quelques cas dans la vie courante où on a besoins de plus de 6 chiffres significatifs, pas beaucoup où on a besoin de plus de 12 (c'est à dire de mieux que des doubles). Ensuite, c'est souvent un simple problème d'affichage : si tu affiches ton "137" avec 3 décimales, il n'y a plus d'erreur visible, si tu forces l'arrondi à la troisième décimale, tu vas même un peu plus loin que le visible.

Dans les cas où les 12 chiffres ne suffisent pas, soit il faut utiliser des représentation encore plus fines (genre des réels sur 12 ou 16 octets), soit il faut choisir des algorithmes où ces erreurs d'arrondi posent peu de problèmes.

Par exemple, quand il s'agit de résoudre des systèmes d'équations, donc couramment d'inverser des matrices, certaines méthodes (genre pivot) bloquent dès qu'on augmente la taille de la matrice (je me souviens avoir utilisé sous mac os 6 :D des réels en "extended" qui me permettaient de faire des approximations polynômiales de degré 12 ou 14 plutôt que 8 ou 10, ce qui suffisait dans le cas qui m'intéressait. S'il avait fallu aller au-delà, vu qu'il n'y avait pas (au moins de façon simple) de représentations adéquates, il aurait fallu changer d'algorithmes, passer par des procédures itératives plus lentes mais où ces problèmes se posent moins. C'est entre autres pour cette raison qu'ont été développés des tas d'algorithmes numériques de type itératif moins sensibles à ces problèmes.

Ce qui est assez "amusant", c'est que les problèmes de précision peuvent être vicieux, les bougres. Exemple typique (celui qui d'ailleurs pose problème pour l'inversion de matrices) quand tu dois manipuler des nombres très différents entre eux, exemple tu soustrais 1.0 de 1.0 e15, forcément, ta soustraction ne fait rien même si tes deux nombres ont l'air très simple : 1 dans les 2 cas mais avec une échelle complètement différente. Il faut donc se débrouiller pour éviter d'avoir des calculs de ce type.

:casse: :casse: :casse: :rateau: :casse: :rateau: :rateau: :casse: :casse: :rateau: :rateau:
Heu, bon ben moi, je retourne au forum arts graphiques...
 
pépé luc :D:D:D /michel simon accent / en 1923 j'avais déjà n**q*é ce p****n de floating-point


le mot IEEE754

http://grouper.ieee.org/groups/754/

tous les languages sont sujet à ce truc et en plus ca change suivant la platforme ...

:D:D:D:D:D t'es pas sortie avec ça :D:D

un petit jeux de floating-point ? :D y'en a bien qui joue au sodoku mon c**l :D

Bloc de code:
(c)tatouille
example darwin-dev-list
/*************************************************************/
#include <stdio.h>
#include <fenv.h>

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

  save_rnd = fegetround();
  if (save_rnd == FE_TONEAREST)
    printf("rounding direction is FE_TONEAREST\n");
  else
    printf("unexpected rounding direction\n");

  x = 1.79e308;
  y = 2.2e-308;
  z = x / y;                      /* overflow */
  printf("%g / %g = %g\n", x, y, z);

  x = -1.79e308;
  y = 2.2e-308;
  z = x / y;             /* negative overflow */
  printf("%g / %g = %g\n", x, y, z);

  fesetround(FE_TOWARDZERO);
  rnd = fegetround();
  if (rnd == FE_TOWARDZERO)
    printf("rounding direction is FE_TOWARDZERO\n");
  else
    printf("unexpected rounding direction\n");

  x = 1.79e308;
  y = 2.2e-308;
  z = x / y;                      /* overflow */
  printf("%g / %g = %g\n", x, y, z);

  fesetround(FE_UPWARD);
  rnd = fegetround();
  if (rnd == FE_UPWARD)
    printf("rounding direction is FE_UPWARD\n");
  else
    printf("unexpected rounding direction\n");
                                                /* continued */
/*************************************************************/
/*************************************************************/
  x = -1.79e308;
  y = 2.2e-308;
  z = x / y;             /* negative overflow */
  printf("%g / %g = %g\n", x, y, z);

/* return to round-to-nearest */
  fesetround(save_rnd);
  rnd = fegetround();
  if (rnd == FE_TONEAREST)
    printf("rounding direction is FE_TONEAREST\n");
  else
    printf("unexpected rounding direction\n");
}
/*************************************************************/
:zen:

:D
J'AI JAMAIS VU CA !!!!:confused::confused:

j'espère que tu n'es pas developpeur ?
 
tatouille a dit:
tous les languages sont sujet à ce truc et en plus ca change suivant la platforme ...

Ben oui, la plate-forme, c'est comme ça qu'on pouvait utiliser les extended sur les 680x0 :D

Pour les langages, il faut prendre des langages à précision arbitraire genre OCaml par exemple (mais tout le monde ne connait pas ce genre de langage :D). Rermarque, ça ne m'étonnerait pas qu'il y ait une bibli java pour faire ça mais comme je suis déconnecté de tout ça depuis longtemps...

Ceci dit, l'avantage de ce genre de problème, c'est que, au moins quand les gens s'aperçoivent qu'il y a un problème, ça peut les forcer à réfléchir à la différence entre math et informatique :D
 
  • J’aime
Réactions: tatouille
:siffle: oui y a un truc pour aider sisi c'est dans la doc
Java en plus a peut etre la doc la mieux faite quand on cherche un truc :D:D:D:D

puis en plus il y a des profs, des chercheurs en math qui ont écrit des trucs pour Java...
:D:D:D:D

c'était la Blague du Mardi offerte par Philou du 9 4
:up::up::up::up::up:
 
Reste la question, que vont devenir A et B ? Quel est vraiment le problème ?
Si c'est pour faire du calcul pur avec des doubles, soit la précision (ou plutôt l'imprécision ;) ) est tolérable, soit t'es dans le caca.

Si c'est pour afficher des nombres, il faut utiliser les classes qui vont bien (NumberFormat ou DecimalFormat ) c'est nécessaire, ne serait ce que pour utiliser les paramètres liés à la langue.
 
tatouille a dit:
J'AI JAMAIS VU CA !!!!:confused::confused:

j'espère que tu n'es pas developpeur ?

je ne sais pas à qui ton message s'adresse :D

Pour ma part, je ne suis plus développeur (et ne l'ai jamais été vraiment) mais je suis toujours confronté à des outils développés par d'autres :D

Je fais joujou avec des boîtiers de télécontrôle qui donnent des résultats intéressants dans leurs calculs suite à ces problèmes d'arrondi, par exemple de bêtes différentiels sur des compteurs qui, parce que le compteur s'est réinitialisé à une valeur élevée (pour des raisons diverses et variées) se retrouvent minorés systématiquement juste de quelques dizaines de pour cent, ce qui leur permet de rester plausibles tout en étant faux.

Comme il s'agit simplement de récupérer des résultats de mesures et pas de développer derrière, ces erreurs peuvent très facilement passer inaperçues, et pousser les gens à se gratter la tête quand ils voient les résultats, vu que les gens en question ne sont généralement ni développeurs, ni matheux. :D
 
BigDecimal pour avoir des réels avec une meilleure précision. Mais ce n'est pas la solution pour le problème de départ.
 
molgow a dit:
BigDecimal pour avoir des réels avec une meilleure précision. Mais ce n'est pas la solution pour le problème de départ.

Le problème de départ, c'est d'abord de savoir quelle est la précision nécessaire :D

Si 6 ou 8 chiffres significatifs suffisent, il faut travailler en double puis afficher avec un format limité à 6 ou 8 chiffres significatifs, il n'y aura plus d'erreur apparente. Et l'erreur réelle ne portera que sur la 11 ou 12ème décimale. Sauf si on cumule pendant un bon moment les erreurs d'arrondi.

Que je sache, ça n'a pas empêché des tas de calculs de se faire depuis le premier ordinateur et le problème a toujours été présent puisqu'il est intrinsèque à la représentation d'une infinité par un ensemble fini. Les erreurs sont choquantes mathématiquement parlant(si on veut travailler "propre" il faut de la précision arbitraire) mais en pratique, il y a peu de situations où en même temps :
- ce soit gênant
- ce ne soit pas contournable en ajustant les algorithmes.
 
Luc G a dit:
Le problème de départ, c'est d'abord de savoir quelle est la précision nécessaire :D

..ement parlant(si on veut travailler "propre" il faut de la précision arbitraire) mais en pratique, il y a peu de situations où en même temps :
- ce soit gênant
- ce ne soit pas contournable en ajustant les algorithmes.

:mouais::eek::eek::eek: avec les impots je verifie au milliardieme de centime d'euro :D:D:D