Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 24/12/2006, à 19:22

nico_h

[résolu] précision d'une multiplication en java

bonsoir,


je rencontre un problème un peu embêtant et qui m'étonne aussi beaucoup : mon ordinateur ne sait pas multiplier correctement deux nombres !!! en fait, ça dépend des cas...

mais bon, voilà le test qui colle pas, c'est une bête fonction java comme suit :

public class FeuilleAutoTest{

  public static void main(String args[]){
    double p = 5.2;
    double q = 3.9;

    System.out.println(p*p);
    System.out.println(q*q);
  }

}

et ça donne en sortie :

nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ javac -d ../classes/ FeuilleAutoTest.java
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ java FeuilleAutoTest
27.040000000000003
15.209999999999999
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$

Les réponses exactes étant 27,04 et 15,21 bien entendu.
(Inutile de préciser qu'en float, le résultat est pire...)

Manque-t-il un réglage quelque part sur mon PC ? Mon processeur a-t-il un problème ?

Vais-je donc devoir moi-même implémenter un algorithme effectuant la multiplication de deux décimaux ??

NB si quelqu'un peut tester ce programme chez lui et m'envoyer son résultat, surtout s'il est différent, ça m'intéresserait ! parce que en principe on devrait avoir le même résultat, c'est du java...


[EDIT:] Et c'est pas tellement mieux avec une bête addition !!! :

nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ cat FeuilleAutoTest.java
import general.*;
import calcullitteral.*;
import geometrie.*;
import java.io.*;


public class FeuilleAutoTest{


  public static void main(String args[]){

    double r = 81;
    double s = 23.04;

    System.out.println(r+s);

  }


}
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ javac -d ../classes/ FeuilleAutoTest.java
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ java FeuilleAutoTest
104.03999999999999
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$

Dernière modification par nico_h (Le 21/11/2010, à 23:41)


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#2 Le 24/12/2006, à 19:59

trucutu

Re : [résolu] précision d'une multiplication en java

J'aime bien le concept: c'est la faute du PC...

Dans ce cas, je pense que c'est plutôt la faute du programmeur...
C'est clairement un problème d'arrondi, et le problème n'est pas réservé à Java, on retrouve cette problématique dans plusieurs langages...

Si tu limites le flot de sortie à deux chiffres après la virgule, ca ne s'arrondi pas correctement ?


La chanson du dimanche - "La pêche !"
PC acheté chez Novatux : entièrement satisfait.
Faire des recherches solidaires !

Hors ligne

#3 Le 24/12/2006, à 20:57

kaworu

Re : [résolu] précision d'une multiplication en java

Salut !
Si ça peut te rassurer, c'est tout à fait normal XD
Le problème étant la représentation des nombres flottant dans la mémoire (je t'épargne les histoire de signe-exposant-matrice standard IEEE etc parce que wikipédia le fera mieux que moi).
Comme on n'a pas une précision infinie, il faut bien arrondire un jour ou l'autre. Un double étant codé sur 64bits, il est plus précis qu'un float, mais il y a toujours des limites. Un exemple tout à fait parlant :

ruby -e 'puts "true" if 1.9 == 1.8 + 0.1'
python -c 'if 1.9 == 1.8 + 0.1 : print "true" '

ou en Java

class foo {
    public static void main(String[] arguments) {
        if (1.9 == 1.8 + 0.1) {
             System.out.println("true");
        }
    }
}

et voilà. C'est pas la faute du programmeur wink


"There are in order of increasing severity: lies, damn lies, statistics, and computer benchmarks."

Hors ligne

#4 Le 24/12/2006, à 21:55

nico_h

Re : [résolu] précision d'une multiplication en java

trucutu a écrit :

J'aime bien le concept: c'est la faute du PC...

Dans ce cas, je pense que c'est plutôt la faute du programmeur...
C'est clairement un problème d'arrondi, et le problème n'est pas réservé à Java, on retrouve cette problématique dans plusieurs langages...

Si tu limites le flot de sortie à deux chiffres après la virgule, ca ne s'arrondi pas correctement ?

Bon ben cool d'apprendre que c'est normal, mais ça me pose un gros problème. Je savais que la précision était pas infinie, mais de là à causer des erreurs aussi grossières... Je veux dire, avec si peu de décimales correctes... et ce, aléatoirement.

Mon problème est que j'ai besoin de calculs précis y compris au-delà de 2 chiffres après la virgule.
Si je faisais cet arrondi systématiquement, y'a plein de cas qui passeraient pas dans mon projet (par exemple, quand je multiplie deux décimaux ayant 2 décimales chacun, ça me donne un décimal à 4 décimales, je peux pas le virer comme ça, faut que je le garde).

Bon, j'ai mis une sorte de "pansement" en calculant pour chaque cas l'arrondi qui ne fera pas mal au nombre pour récupérer un résultat correct. Ca complique pas mal mon code, mais bon...

Merci pour les réponses en tous cas ! Au moins je sais que j'ai pas le choix...
Si j'avais su j'aurais programmé l'addition et la multiplication de décimaux moi-même !!! et les autres opérations aussi, d'ailleurs... mince, quoi... c'est pas la mer à boire d'additionner deux décimaux à 2 chiffres après la virgule correctement !! Enfin... pour le moment, mon prog marche avec des béquilles... bref allez j'ai besoin de repos, je crois...

J'ai testé la ligne python, en effet, c'est parlant...

Encore merci !

Dernière modification par nico_h (Le 24/12/2006, à 22:03)


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#5 Le 25/12/2006, à 00:24

trucutu

Re : [résolu] précision d'une multiplication en java

Relativise un peu.
Regardes tes deux premiers résultats ils sont corrects.
Le problème, je pense, vient plutôt de l'utilisation de la fonction d'affichage qui n'est peut être pas la plus adaptée ou qui est incorrectement utilisée...


La chanson du dimanche - "La pêche !"
PC acheté chez Novatux : entièrement satisfait.
Faire des recherches solidaires !

Hors ligne

#6 Le 25/12/2006, à 02:35

nico_h

Re : [résolu] précision d'une multiplication en java

trucutu a écrit :

Relativise un peu.
Regardes tes deux premiers résultats ils sont corrects.
Le problème, je pense, vient plutôt de l'utilisation de la fonction d'affichage qui n'est peut être pas la plus adaptée ou qui est incorrectement utilisée...

Mais... System.out.println fait partie des fonctions livrées avec Java, dans les paquets standards (je sais plus le nom). Il n'y a pas de format à y appliquer comme en C (je crois, ça fait longtemps)... faut juste lui filer des chaînes (et elle convertit automatiquement en chaîne toute instance d'une classe possédant la méthode toString(),  et pour les types primitifs comme "double" ou "int" etc. elle se débrouille aussi à forcer la conversion, sinon de toute façon si on lui file un truc qui va pas ça fait erreur à la compil).

Non, non, le problème c'est bien que la précision des calculs est mauvaise et puis c'est tout. Dans mon cas de projet c'est très gênant et pour ça j'ai dû mettre un double "pansement" sur les calculs cruciaux consistant 1°) à arrondir à 10 chiffres après la virgule pour "rattraper" les nombres du genre 3,999999999999 et 2°) à arrondir pendant les calculs pile à la précision nécessaire (par exemple, arrondir au dix-millième le résultat d'un produit de deux décimaux ayant 2 décimales chacun). Apparemment après tests nombreux ça fonctionne, mais je ne suis pas certain que cela n'entraîne pas un bug chelou dans un cas imprévu qui ne se produit qu'une fois sur cent ou mille, par exemple. Tout ça à cause de calculs qui devraient fonctionner correctement, je trouve, pour la précision demandée... je demanderais à 14 chiffres après la virgule, je dis pas, mais à 2 ou 3 chiffres, quand même... n'importe quel convertisseur en euros fait mieux ! Bon, je verrai bien à l'usage.

Allez au dodo il est bien temps... zzzzzzzzzz


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#7 Le 25/12/2006, à 11:09

nico_h

Re : [résolu] précision d'une multiplication en java

Je vais tenter une utilisation de "BigDecimal", ça pourrait être une solution efficace à mon problème... Joyeux Noël à tout le monde !!



[EDIT] il y a certes un gain de précision mais en fait, c'est pas gagné !

nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ cat FeuilleAutoTest.java
import java.io.*;
import java.math.*;


public class FeuilleAutoTest{


  public static void main(String args[]){

    BigDecimal n = new BigDecimal(5.2);


    System.out.println("en double : " + n.doubleValue()*n.doubleValue());

    System.out.println(n.multiply(n));


  }


}
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ java FeuilleAutoTest
en double : 27.040000000000003
27.0400000000000018474111129762605148193593045435972164691426113114491869282574043609201908111572265625
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$

neutral

Dernière modification par nico_h (Le 25/12/2006, à 11:17)


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#8 Le 25/12/2006, à 11:41

nico_h

Re : [résolu] précision d'une multiplication en java

Reste à tester cela de façon plus fouillée, sur d'autres calculs plus "compliqués" mais...


nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ cat FeuilleAutoTest.java
import java.io.*;
import java.math.*;


public class FeuilleAutoTest{


  public static void main(String args[]){

    BigDecimal n = new BigDecimal("5.2");


    System.out.println("en double : " + n.doubleValue()*n.doubleValue());

    System.out.println(n.multiply(n));


  }


}
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ java FeuilleAutoTest
en double : 27.040000000000003
27.04
nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$

smile ça commence à ressembler à ce qu'il me faut !


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#9 Le 25/12/2006, à 21:08

trucutu

Re : [résolu] précision d'une multiplication en java

Je suis désolé d'insister et de ne pas trop connaître Java pour bien t'aider, mais je pense qu'il y a un problème avec l'interprétation d'un double avec println qui prend un string en argument, ou un truc dans le genre. Ca ne te sembles pas bizarre qu'elle affiche toujours x chiffre après la virgule, alors qu'elle devrait afficher un compte rond ?

Dans le site suivant, ils ont l'air de faire une manip spéciale pour afficher des double :
http://www.ac-creteil.fr/util/programma … nees1.html
Ca ne résoud pas ton problème ?

Je le répète, les résultats sont corrects. Pour n'importe quel scientifique qui ne travaille pas dans la précision nucléaire, 27.04000000000000003 vaut 27.04. Ton ordirnateur est juste un outil de calcul. Si tu n'interprètes pas les résultats de ce qu'il affiche avec un minimum de logique, ton programme sera inutile... D'où la phrase choc de mon premier post. C'est quelque chose que tu apprendras sûrement en grandissant (Ne le prend pas mal, stp...)


La chanson du dimanche - "La pêche !"
PC acheté chez Novatux : entièrement satisfait.
Faire des recherches solidaires !

Hors ligne

#10 Le 25/12/2006, à 23:25

nico_h

Re : [résolu] précision d'une multiplication en java

trucutu a écrit :

Je suis désolé d'insister et de ne pas trop connaître Java pour bien t'aider, mais je pense qu'il y a un problème avec l'interprétation d'un double avec println qui prend un string en argument, ou un truc dans le genre. Ca ne te sembles pas bizarre qu'elle affiche toujours x chiffre après la virgule, alors qu'elle devrait afficher un compte rond ?

Ce n'est pas *toujours* le même nombre de chiffres. J'ai pris des exemples de cas qui me foirent mon programme. Mais ils n'arrivent que de temps en temps. Disons que 7 à 8 fois sur dix, y'a pas de soucis (et pas tant de chiffres après la virgule).

Par contre j'ai *toujours* besoin de résultats précis.

Si tu veux comprendre le problème, voici son exposé complet :

*J'ai besoin* de déterminer si un arrondi à la fin d'une suite de calculs est nécessaire. Par exemple, s'il s'agit d'une racine carrée qui ne tombe pas juste (comme racine carrée de 2) et que l'énoncé a demandé un résultat de calcul arrondi au centième, je vais afficher la fin du calcul avec un signe "égale environ" au lieu du signe "=" habituel et je rajouterai une petite phrase rappelant que le résultat est arrondi. S'il n'y a pas besoin de faire d'arrondi (par exemple, on tombe "pile" sur le résultat 12,56 et l'énoncé a demandé un arrondi au centième), j'afficherai le résultat avec un signe "=" et sans commentaire particulier. Mon problème est donc plus compliqué que la simple obtention et interprétation d'un résultat (merci, je sais faire !).

Pour y répondre :
1°) je dois donc déterminer avant affichage des dernières lignes si le résultat final (au terme d'un calcul qu'aurait pu faire un être humain) *nécessite* un arrondi. Or, si je me contente de faire la différence entre le résultat "brut" livré par le PC et le résultat arrondi comme demandé dans l'énoncé, le test rate nécessairement dans les cas que j'ai présentés en début de topic. En effet, il va s'apercevoir, par exemple, qu'entre 27,04 et 27,040000000000003 il y a une différence et affichera un résultat présenté comme approché alors qu'en réalité il est exact !

2°) j'ai donc pensé à un premier "pansement" consistant à arrondir à 4 ou 5 chiffres après la virgule le nombre servant à la comparaison. Ainsi 27,040000000000003 arrondi au dix-millième donnant 27,04 la différence avec 27,04 est nulle et c'est bon on voit qu'il n'y a pas besoin d'arrondi. Mais apparaissent alors des "contre-cas" ! Situation inverse ! Cas particuliers d'un calcul qui ne tombe pas juste, qui nécessite donc un arrondi et que le programme ne détecte pas et affiche comme résultat exact alors qu'il est approché ! Exemple de ce genre, un calcul se terminant par l'affichage de la valeur approchée de la racine carrée de 392 au dixième près. Cette racine carrée a pour valeur décimale approchée 19,7989898732... donc son arrondi au dixième est 19,8 (pas de souci pour obtenir cette valeur) seulement quand tu fais l'arrondi à 4 ou 5 chiffres (et même jusqu'à 7 chiffres après la virgule dans ce cas-là), tu tombes *aussi* sur 19,8. Donc la différence est nulle et le PC ne détecte pas qu'il s'agit en fait d'un arrondi et le présente comme résultat exact. Il affiche donc que la racine carrée de 392 est exactement 19,8, tout ça à cause du pansement servant à éviter le buug inverse précédent ! C'est tordu comme problème ! Du coup j'ai "décalé" mon pansement à un arrondi à 10 chiffres après la virgule. Ce n'est qu'un pansement car dans le cas où une racine carrée qui ne tombe pas juste n'a que des chiffres compris entre 5 et 9 de la première à la 10ième décimale, ça va encore foirer ! Cela dit, la probabilité que le cas se présente est faible et donc le programme fonctionne actuellement de façon satisfaisante.

3°) dans tout ça, j'avais aussi à afficher des nombres entiers en tant que nombres entiers et non comme des 3,999999999999999 et autres 18,0000000000001. Le second pansement résoud ce problème a priori.

Conclusion, je pourrai enlever mes pansements quand mes calculs sur des nombres ayant deux à quatre chiffres maximum après la virgule seront tous exacts, ce qui ne me paraît pas inaccessible. C'est la seule solution pour un programme "robuste" qui affiche ce que je veux dans *tous les cas* et pas seulement 99 fois sur 100.

Si l'utilisation de BigDecimal en passant une chaîne au constructeur est satisfaisante comme semble le laisser croire mon dernier test, je m'en servirai.

Sinon j'implémenterai moi-même une classe effectuant pour ce genre de décimaux les opérations arithmétiques élémentaires usuelles de façon exacte (faisable dans la mesure où les additions de nombres entiers le sont) et étant donc capable de comparer sans faille des décimaux de ce genre (càd des "vrais" décimaux mathématiques, on ne pourra pas comparer des irrationnels entre eux je pense). Evidemment cela ralentira le programme mais ça je m'en moque car je n'ai pas vraiment de contrainte temporelle cruciale.

J'ai par ailleurs suivi ton lien mais ça ne résoud pas grand chose... il explique seulement la souplesse de java en matière de types et de classes. Càd que la méthode println() de System.out effectue les conversions de type ou de classe automatiquement. En fait, j'en sais même un chouilla plus que ce qui est présenté dans cette page, car cela est d'une part implémenté pour les types primitifs (dont double) et cela est possible pour tout objet d'une classe implémentant une méthode toString(), ce qui est le cas des classes enveloppes comme Double, Integer, BigDecimal et consorts.

Le problème n'est certainement pas un problème lié à l'affichage (ou sinon, j'aimerais avoir une doc précise sur ce sujet), mais bien de précision dans les calculs (qui nuit à ce que je veux faire ! je répète que mon problème n'est pas seulement d'obtenir un résultat à interpréter par moi-même. Si tu ne comprends pas toutes mes explications précédentes, considère qu'il est équivalent de se représenter que je travaille dans la précision nucléaire big_smile).


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#11 Le 26/12/2006, à 00:33

trucutu

Re : [résolu] précision d'une multiplication en java

nico_h a écrit :

Mon problème est donc plus compliqué que la simple obtention et interprétation d'un résultat (merci, je sais faire !).

Tu veux faire le distingo ( "=" et "~=" ) dans ton programme ?
Il suffit de traduire ce que tu explique ensuite en algorithme.

Sur certaines opérations (+ - * ), tu connais la nature exacte du résultat ainsi que le nombre de décimales, donc ça c'est réglé.

Pour d'autre ( / et racines ... ), la nature de l'opération a de grandes chances d'être inexacte et tu devras sûrement tronquer arbitrairement le résultat.

Je ne suis pas un expert en calcul numérique, mais si tu veux être rigoureux en ce domaine, tu as du boulot... Pour la division, tu peux implémenter l'algorithme d'euclide pour savoir si tu auras un reste null ou non. Pour les racines, je ne vois pas trop à froid comment tu peux faire, désolé.

Je ne savais pas qu'on travaille en précision nucléaire en programmant en Java en classe de 4°... Dire qu'on entend parler d'un nivellement par le bas à l'école. Il faut se réjouir, les futurs ingénieurs seront facilement capables de résoudre les grands problèmes scientifiques actuels !!

bon courage


La chanson du dimanche - "La pêche !"
PC acheté chez Novatux : entièrement satisfait.
Faire des recherches solidaires !

Hors ligne

#12 Le 19/05/2007, à 12:03

Sebbane

Re : [résolu] précision d'une multiplication en java

nico_h a écrit :

Reste à tester cela de façon plus fouillée, sur d'autres calculs plus "compliqués" mais...


nico@tezcatlipoca:~/Classe_de_4ieme/FeuillesAuto/sources$ cat FeuilleAutoTest.java
import java.io.*;
import java.math.*;


public class FeuilleAutoTest{


  public static void main(String args[]){

    BigDecimal n = new BigDecimal("5.2");


    System.out.println("en double : " + n.doubleValue()*n.doubleValue());

    System.out.println(n.multiply(n));


  }


}

si a la place de     BigDecimal n = new BigDecimal("5.2");  on veut mettre  BigDecimal n = new BigDecimal(1/3);  on aura comme résultat 0.0 , alors que normalement c 1.33333....
moi ce que je veux c de faire un calcule (1/3) et afficher le résultat
merci pour votre aide
a++

#13 Le 19/05/2007, à 13:12

nico_h

Re : [résolu] précision d'une multiplication en java

Je ne me suis pas encore attelé à ce travail... d'autres projets en cours mais j'y reviendrai !

@ Sebbane je ne vois pas trop la difficulté, pour le coup. Tu devrais peut-être te ballader sur des forums spécialisés java pour en savoir plus...
Je ne peux que te proposer un truc simple comme :

public class Essai{

  public static void main(String args[]){
    double p = 1;
    double q = 3;

    System.out.println(p/q);
  }

}

et en fait, sans variable, ça devrait marcher direct (System.out.println(1/3)))

ou bien je n'ai pas compris ton problème


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#14 Le 19/05/2007, à 20:01

nico_h

Re : [résolu] précision d'une multiplication en java

au fait, depuis le mois de décembre je n'ai pas rien fait : le résultat de tout ce travail est consultable en ligne depuis quelque temps ! bon, alors, c'est plutôt pour des élèves de 4e et c'est pas encore très fourni (ça grossira gentiment avec les années : j'aime bien mais j'ai pas que de la prog à faire dans la vie smile )

donc c'est là : http://mr.hainaux.net/ et plus précisément ça se trouve dans le générateur d'exercices : ceux sur le théorème de Pythagore. c'est la partie "corrigé" (en 2e page de la feuille d'exos sur le thm de Pythagore) qui m'a posé problème avec ces histoires d'arrondis à la mord-moi-le-n****

par ailleurs, y'a un truc html que j'arrive pas à faire sur la page d'accueil et je vais mettre un sujet pour poser la question dans le forum approprié :
http://forum.ubuntu-fr.org/viewtopic.ph … 94#p937394

Dernière modification par nico_h (Le 19/05/2007, à 20:03)


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#15 Le 20/05/2007, à 00:16

slapierre

Re : [résolu] précision d'une multiplication en java

Je viens ajouter mon grain de sel sur un aspect qui n'à pas été couvert encore : mathématiquement, de par l'axiome de complétude (heu... pas directement, mais oui), les développements décimaux suivants sont égaux :

   1. 23.03999999999...
   2. 24.04

Ce qui fait que l'on ne doit jamais comparer directement deux nombre réels dans un programme puisque tu ne peux savoir si la taille de la période est infinie. Étant donné que la représentation est tronquée, on doit utiliser un "epsilon" pour les opérations sur les points flottants. Typiquement, la valeur de epsilon et de 1/2^(taille de la mantisse), en langage C, ces valeurs sont définies dans limits.h :

float : 1/2^23 = 1.1921e-07
double : 1/2^52 = 2.2204e-16

Si tu veux avoir quelque chose de vraiment précis, le mieux serait de gérer des nombres comme des fractions continues "f = e + n/d", où f est un point flottant et e, n et d sont des entiers non signés (des unsigned long long?). Tu codes un algorithme pour déterminer la fraction continue généralisée, ce qui te permet de faire un constructeur auquel tu passes f. Tu surcharges les opérateurs et tu effectues tes calculs seulement avec tes fractions. Quand tu dois afficher, tu prend les décisions nécessaires.

http://fr.wikipedia.org/wiki/Fraction_continue

>>> 18,0000000000001 devient  "18 + 1 / 10^13"
>>> 2^½ devient "1 + 4142 / 10000" (selon la précision demandée)

Simon

edit: finir ma phrase sur la période. petite erreur pour la racine de 2 roll

Dernière modification par slapierre (Le 20/05/2007, à 17:55)


"Le spectre de la folie nous empêchera-t-il de hisser l'étendard de l'imagination?" - André Breton

Hors ligne

#16 Le 20/05/2007, à 00:39

nico_h

Re : [résolu] précision d'une multiplication en java

Excellent ! Eh bien, comme dit un peu plus haut je n'ai pas le temps actuellement de me pencher sérieusement sur le sujet mais le temps venu, ce post me sera probablement fort utile ! Merci beaucoup !


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#17 Le 13/11/2010, à 21:17

nico_h

Re : [résolu] précision d'une multiplication en java

Bon depuis tout ce temps, j'ai recommencé mon projet en python en lieu et place de java, et la classe decimal.Decimal paraît absolument en adéquation avec mes besoins.

http://docs.python.org/library/decimal.html

>>> a = decimal.Decimal(str(1.9))
>>> b = decimal.Decimal(str(1.8)) + decimal.Decimal(str(0.1))
>>> print b
1.9
>>> print a
1.9
>>> print a == b
True
>>> a = decimal.Decimal(4)
>>> print a
4
>>> b = a.sqrt()
>>> print b
2
>>> c = decimal.Decimal('5.2')
>>> print c*c
27.04
>>> d = decimal.Decimal('3.9')
>>> print d*d
15.21
>>>

On va voir en vrai si ça tourne !


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#18 Le 21/11/2010, à 14:06

Renorems

Re : [résolu] précision d'une multiplication en java

Salut,

Je vais essayer de te faire comprendre les résultats que tu obtiens. Les processeurs calculent en utilisant une représentation binaire des opérandes.

Prenons 6 + 4.
Convertissons 6 en binaire : 6 = 1 x 2^2 + 1 x 2^1 + 0 * 2^0 = 0b110 (j'utilise le préfixe 0b pour indiquer la base 2)
Pour 4 : 4 = 1 x 2^2 = 0b100

0b110 + 0b100 = Ob1010 (10 en décimal)

Dans ce cas tout va bien, on trouve bien que 6 + 4 = 10.

Prenons le cas des flottants. Pour convertir un flottant en binaire, pour la partie entière on fait comme plus haut.

Prenons 2,75. Partie entière 2, donc la partie entière est 0b10.

Pour la partie flottante, la conversion utilise les puissances négatives de 2.

Donc 2,75 : 1 x 2^2 + 0 x 2^1 + 0 x 2^0 + 1 x 2^(-1) + 1 x 2^(-2) = 0b10,11

Ici j'ai choisi le nombre pour que la conversion utilise un nombre fini et petit de chiffre. Mais si on prend ton exemple du début 3,9 :

(je ne converti que la partie décimal)
0,9 = 1/2+1/4+1/8+0/16+0/32+1/64+1/128+0/256+0/512 ... A ce stade on est arrivé à 0,8984375. Je ne suis pas sûr qu'il soit possible d'arriver à 0,9, je pense même que non (flemme de poursuivre le calcul)

Du coup une addition de ce simple nombre avec un autre va générer un résultat imprécis. Note quand même que ce n'est pas toujours le cas. Calcule 2,75 + 0,5 pour t'en assurer.

Pour régler ce soucis, une des (nombreuses) solutions consiste à travailler avec des nombres rationnels. En C++ je ferais une classe fraction. 5,2 = 26/5, 3,9 = 39/10. La multiplication donne (26*39)/(5*10) = 1014/50 = 507/25.

Hors ligne

#19 Le 21/11/2010, à 23:41

nico_h

Re : [résolu] précision d'une multiplication en java

Merci pour cette explication et ce rappel clair du stockage des nombres dans l'ordi ! Et c'est en effet la façon dont les float sont gérés qui pose problème.

Dans mon cas, en python, l'emploi de la classe Decimal du module decimal mentionné dans mon dernier post semble remplir parfaitement son rôle. Je suppose que la classe BigDecimal de Java aurait également résolu le problème. En C/C++ je ne vois en effet pas de meilleure solution que de recréer une classe (ou un truc imitant les classes, avec un struct, en C) qui réimplémente les opérations élémentaires sur les décimaux à partir d'int (ou bien sous forme de fractions décimales comme tu proposes).

Allez,  je mets le sujet en [résolu].

Bonne soirée !


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne

#20 Le 22/11/2010, à 01:52

grim7reaper

Re : [résolu] précision d'une multiplication en java

nico_h a écrit :

Merci pour cette explication et ce rappel clair du stockage des nombres dans l'ordi !

Sauf que c'est faux, les réels sont stockées en virgule flottante et non pas en virgule fixe (sauf architecture particulière).
M'enfin, le problème final reste le même.

Hors ligne

#21 Le 22/11/2010, à 18:50

nico_h

Re : [résolu] précision d'une multiplication en java

OK, merci pour cette précision complémentaire (et donc on lira utilement la page wikipédia sur les virgules flottantes, peut-être ?)
http://fr.wikipedia.org/wiki/Virgule_flottante

Je savais bien depuis le départ qu'il y avait des approximations, mais je ne m'attendais pas à ce que l'ordinateur n'arrive pas à donner des résultats exacts sur des calculs aussi simples que ceux de mon premier post.

Au passage, en python, je constate que ces mêmes calculs ne posent pas de problème à première vue :

>>> p = 5.2
>>> q = 3.9
>>> print p*p
27.04
>>> print q*q
15.21
>>> print type(p)
<type 'float'>
>>> 

Ce sont pourtant bien des float, mais peut-être pas de la même précision que les float de java ?? Enfin n'importe, avec une classe dédiée à ce genre de calculs arithmétiques, c'est réglé !


Config. actuelle : linux mint 22.04 | FreeBSD 12
Des exercices d'entraînement en maths : http://mr.hainaux.net/

Hors ligne