[résolu] calcul faux

calcul faux [résolu] - Java - Programmation

Marsh Posté le 18-09-2006 à 11:08:21    

[résolu] : On va multiplier par 100, merci  :jap:  
 
Bonjour,
 
Petits soucis : je me relance dans la prog Java avec quelques oublis....
 
Je récupère dans un fichier un montant (float) et un nombre (int).
Je récupère donc cela dans des chaines de caractères que je convertis ensuite en float ou int.
 
float montant = Float.parseFloat("7.7" ); //Exemple d'une valeur que je peux avoir
int nombre = Integer.parseInt("3" );
// Ensuite produit classique
float total = montant * nombre.
 
[#f0000e]Et là, au lieu d'avoir 23.1, j'ai 23,09.............. (pleins de chiffre derrières)
 
??? Une idée ?
 
Merci d'avance.


Message édité par moustik510 le 18-09-2006 à 12:04:57
Reply

Marsh Posté le 18-09-2006 à 11:08:21   

Reply

Marsh Posté le 18-09-2006 à 11:09:40    

les nombres décimaux sont rarement stockés sous leur forme exact , mais sous une valeur approchée ( d'assez pres )  
 

Reply

Marsh Posté le 18-09-2006 à 11:16:57    

OK donc la dessus je fais un arrondi à deux décimales près pour obtenir mon montant exact. (C'est la solution temporaire que j'avais utilisé mais je voulais avoir une explication !)
C'est la meilleure solution ?
 
Merci en tout cas pour ta réponse super rapide.

Reply

Marsh Posté le 18-09-2006 à 11:18:04    

utilises des doubles au lieu des floats et tu auras le resultat que tu veux :)


---------------
Mon feedback
Reply

Marsh Posté le 18-09-2006 à 11:19:55    

oui car les nombres pseudo-réels sont stockés en binaire, par puissance de 2 successives.
 
or, 0.1 ne peut pas être stocké entièrement par puissance de 2 (0.0625+0.03125 etc)


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 18-09-2006 à 11:20:24    

gocho a écrit :

utilises des doubles au lieu des floats et tu auras le resultat que tu veux :)


ça ne change rien au problème, ça le repousse


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 18-09-2006 à 11:27:22    

jagstang a écrit :

ça ne change rien au problème, ça le repousse


 
Que faire dans un tel cas alors ?
stocker les valeurs * 2 ?

Reply

Marsh Posté le 18-09-2006 à 11:28:01    

Je savais que Java n'était pas le meilleur langage pour faire des calcul mais quand même là :D
 

Code :
  1. int nombre1 = 3;
  2.         int nombre2 = Integer.parseInt("3" );
  3.         double montant = 7.7 ;
  4.         float montant2 = Float.parseFloat("7.7" );
  5.         double montant3 = Double.parseDouble("7.7" );
  6.        
  7.         System.out.println( nombre1*montant + " " + nombre2*montant2 + " " + nombre2*montant3 );


ça me donne 23.1 23.099998 23.1
 
Netbean me prévient d'une possible perte de précision avec "montant" en float. En prennant des double le résultat semble meilleur mais c'est pê reculer pour mieux sauter, que ce passe-t-il avec un "gros" double ?


---------------
"L'informatique n'est pas plus la science des ordinateurs que l'astronomie n'est celle des télescopes." Michael R. Fellows & Ian Parberry
Reply

Marsh Posté le 18-09-2006 à 11:29:37    

moustik510 a écrit :

Que faire dans un tel cas alors ?
stocker les valeurs * 2 ?


je vois pas ce que ça change  :sweat:


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 18-09-2006 à 11:29:59    

une solution con aussi : calculer en centimes (avec des entiers donc)


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 18-09-2006 à 11:29:59   

Reply

Marsh Posté le 18-09-2006 à 11:40:25    

dès que tu fais du monétaire il __faut__ travailler avec des types entiers (j'ai pas dit int, j'ai dit type entier, arithmétique entière). Si t'as un flottant dans le tas, c'est foutu.

Reply

Marsh Posté le 18-09-2006 à 11:51:36    

Ricco a écrit :

Je savais que Java n'était pas le meilleur langage pour faire des calcul mais quand même là :D
 
Netbean me prévient d'une possible perte de précision avec "montant" en float. En prennant des double le résultat semble meilleur mais c'est pê reculer pour mieux sauter, que ce passe-t-il avec un "gros" double ?


 
le problème est le même dans tous les langages  
regarde sur cette page : http://www.arcanapercipio.com/gen/binaire/bin-nb.php la partie http://www.arcanapercipio.com/gen/binaire/bin-nb.php
 
 

jagstang a écrit :

une solution con aussi : calculer en centimes (avec des entiers donc)


 

Taz a écrit :

dès que tu fais du monétaire il __faut__ travailler avec des types entiers (j'ai pas dit int, j'ai dit type entier, arithmétique entière). Si t'as un flottant dans le tas, c'est foutu.


 
+1  
si tu dois aller au millieme de centime pret , tu multiplie toutes nombres par 100 000
lors de l'affichage tu fais la manip inverse

Reply

Marsh Posté le 18-09-2006 à 11:58:53    

Ricco a écrit :

Je savais que Java n'était pas le meilleur langage pour faire des calcul mais quand même là :D


Ce problème n'a strictement aucun rapport avec Java et n'est en rien spécifique à l'utilisation de Java, il trouve son origine dans la représentation binaire des nombres flottants (norme IEEE754): certains nombres flottants décimaux exacts ne peuvent être encodés de manière exacte en binaire. Tous les langages utilisant un type réel "floating-point" sont affectés. Certains langages disposent par ailleurs d'un type réel "fixed-point" dont la précision est exacte et fixée sur une range donnée, et d'un type "decimal" à la précision infinie (mais notablement moins efficace, et prenant largement plus de place)
 
De même que certaines fractions ne peuvent être encodées de manière exacte en décimal (1/3 ~ 0.333~)
 
Merci, donc, d'arrêter de raconder des conneries, et de lire What Every Computer Scientist Should Know About Floating-Point Arithmetic


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 18-09-2006 à 12:00:44    

flo850 a écrit :

+1  
si tu dois aller au millieme de centime pret , tu multiplie toutes nombres par 100 000
lors de l'affichage tu fais la manip inverse


 
Ah ... ça me dis quelque chose ça. on a du me le dire pendant les cours... mais j'ai pas du le noter. Et je n'utilise pas Java professionnellement (dev SAP) donc j'évolue pas.
 
Je vais faire de la multiplication par 100. Merci pour vos réponse. Comment passer le sujet en résolut ?

Reply

Marsh Posté le 18-09-2006 à 12:01:59    

edit ton premier post


---------------
What if I were smiling and running into your arms? Would you see then what I see now?  
Reply

Marsh Posté le 18-09-2006 à 13:11:52    

Reply

Marsh Posté le 18-09-2006 à 15:11:25    

Taz a écrit :

BigDecimal :o


 
C'est pour toi la meilleure solution ?
(Sachant que je ne travaillerai pas avoir des nombres très grands mais pour être plus propre ...)

Reply

Marsh Posté le 18-09-2006 à 15:22:11    

Decimal tout court doit faire l'affaire logiquement. A moins qu'e Java Decimal soit un alias de Float, il utilise une précision fixe, et donc ne pose pas ces problèmes d'approximation (si ?)
Mais sinon, *100 et dans un Int ça reste de loin la meilleure solution.

Message cité 1 fois
Message édité par MagicBuzz le 18-09-2006 à 15:22:40
Reply

Marsh Posté le 18-09-2006 à 15:43:25    

MagicBuzz a écrit :

Decimal tout court doit faire l'affaire logiquement. A moins qu'e Java Decimal soit un alias de Float, il utilise une précision fixe, et donc ne pose pas ces problèmes d'approximation (si ?)
Mais sinon, *100 et dans un Int ça reste de loin la meilleure solution.


Si. Il suffit de faire 3 * 0.7. Ce qui est donc complètement pourri. En compta t'es pas la pour jouer à madame irma. le Calcul doit être exact du début jusqu'à la fin. Si tu fais une somme de float, l'imprécision se propage et grandit linéairement. Et là tu plantes ta compta.
 
BigDecimal c'est très bien, et t'auras une bonne propagation d'échelle que tu pourras gérer toi même. Par exemple du fais un calcul avec la précision maximale genre 175.25 * 0.03 ça va te faire du 5.2575 et quand tu enregistres tes données, tu peux tronquer. Comme ça c'est parfait, tu as fait le calcul exact tout le long.

Reply

Marsh Posté le 18-09-2006 à 15:55:50    

Ma question était : est-ce que Decimal en Java est comme le Decimal en SQL, c'est à dire TOUT SAUF UN FLOAT. (en réalité, une chaîne de caractères d'un nombre fixe de chiffres).
 
Ce type (en SQL tout du moins) permet de stocker des valeurs à virgule d'une façon très précise, sans le moindre risque d'erreur d'arrondi.
 
Et Decimal tout court devrait suffir amplement. BigDecimal, comme tout "big", n'est qu'une solution pourrie pour repousser le problème d'arrondi, sans s'en protéger.
 
Dans tous les cas, une application COMPTA ne compte qu'en entiers, ou en types à précision fixe (Decimal en SQL donc). Jamais de la vie en float, même si c'est un float sur 64 bits avec une "grande précision" car dès qu'on fait 1 + 1, même avec 64 bits de précision, un float va faire une erreur de calcul. Avec un type Decimal, ce n'est pas le cas, à moins qu'on ne dépasse le nombre de chiffres pour la représentation. (gare au /3 par exemple)


Message édité par MagicBuzz le 18-09-2006 à 15:56:43
Reply

Marsh Posté le 18-09-2006 à 15:56:21    

Je reprécise : BigDecimal c'est bien mieux que des int parce que dans ta compta, tu as des multiplication avec des fractions, et le temps de l'opération, tu as besoin (obligatoire) de précision supplémentaire. C'est vraiment important quand le calcul doit être exact.
 
Surtout avec des float, quand tu mélanges des nombres d'ordre très différents, ça devient très tendu.

Reply

Marsh Posté le 18-09-2006 à 15:56:35    

moustik510 a écrit :

Ah ... ça me dis quelque chose ça. on a du me le dire pendant les cours... mais j'ai pas du le noter. Et je n'utilise pas Java professionnellement (dev SAP) donc j'évolue pas.
 
Je vais faire de la multiplication par 100. Merci pour vos réponse. Comment passer le sujet en résolut ?


quitte a mettre en place un systeme de ce type , garde toi un peu de marge : multiplie pas 1 000 ou 10 000

Reply

Marsh Posté le 18-09-2006 à 15:58:21    

oui BigDecimal c'est comme celui du SQL.
 
je connais pas Decimal en java, juste java.math.BigDecimal.

Reply

Marsh Posté le 18-09-2006 à 16:00:05    

A priori, y'a pas de raison pour que Decimal ne soit pas pareil que BigDecimal donc ;)
 
Sauf que l'un doit avoir une précision de 40 chiffres alors que l'autre n'a une précision que de 20 chiffres mettons. (à compter que Decimal existe hein, moi je ne connais pas Javs ;))
 
Toujours est-t-il que dans ce cas, je suis d'accord avec ta solution. BigDecimal est dont parfaitement adapté, car garantie une précision fixe, ce qu'on utilise effectivement en compta.
 
Et oui, en compta :
 
10.00 / 3 * 3 = 9.99 et non 10 ! (d'où l'importance de travailler en précision fixe)


Message édité par MagicBuzz le 18-09-2006 à 16:01:49
Reply

Marsh Posté le 18-09-2006 à 16:21:41    

sauf que Decimal en java ca n'existe pas [:pingouino]

Reply

Marsh Posté le 18-09-2006 à 16:24:41    

Ben forcément :spamafote:
 
C malin aussi d'appeler un champ Bigxxx alors que le type "de base" n'existe pas :o

Reply

Marsh Posté le 18-09-2006 à 16:58:49    

c'est pour avoir la plus grosse :o

Reply

Marsh Posté le 28-10-2006 à 18:12:55    

Taz a écrit :

l'imprécision se propage et grandit linéairement.


Il n'y a pas de raison que l'évolution de l'imprécision soit linéaire :)
 
Sinon, juste pour compléter les réponses, un nombre à virgule flottante est composé de 3 "champs": un bit de signe, un exposant, une mantisse (S|E|M).
Pour un float, 32 bits, répartis comme ceci : (1|8|23).
Pour un double, 64 bits, répartis comme ceci : (1|11|52).
 
Le nombre de chiffres significatifs est donc de 23 en base 2 pour un float (donc 23 * ln2/ln10 ~= 7 en base 10) et de 52 en base 2 pour un double (donc 52 * ln2/ln10 ~= 16 en base 10).
 
Ca c'est pour le stockage "brut". Après, c'est les opérations qui font perdre de l'imprécision, notamment l'addition de 2 nombres d'ordre de grandeur très différents (absorption) ou la soustraction de 2 nombres très très proches (cancellation).
Les multiplications n'entraîne pas de perte d'information autre que celle du stockage du résultat.

Reply

Marsh Posté le 08-11-2006 à 09:54:39    

rom1v a écrit :

Il n'y a pas de raison que l'évolution de l'imprécision soit linéaire :)

tu as raison, c'est toujours pire que linéaire.

Reply

Marsh Posté le 08-11-2006 à 10:08:27    

Petite correction par rapport à ce que j'ai dit, le nombre de chiffres significatifs est la taille de la mantisse + 1 (car il y a un 1 implicite), et donc pour un float, 23 chiffres significatifs en base 2, et en double 53...

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed