[Maxima] Résultat étrange pour une simple soustraction

Tout ce qui concerne notamment les outils de calcul numérique, de calcul formel ou de géométrie.
[participation réservée aux membres inscrits]
Règles du forum
Merci de soigner la rédaction de vos messages et de consulter ce sujet avant de poster. Pensez également à utiliser la fonction recherche du forum.
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

[Maxima] Résultat étrange pour une simple soustraction

Message non lu par MB »

Bonjour, en utilisant Maxima, je constate que :

Code : Tout sélectionner

17.64-15.84;
retourne le résultat suivant :

Code : Tout sélectionner

1.800000000000001
Je ne parviens pas à l'expliquer ...
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
Arnaud
Modérateur honoraire
Modérateur honoraire
Messages : 7095
Inscription : lundi 28 août 2006, 13:18
Localisation : Allemagne

Message non lu par Arnaud »

Erreur d'arrondis à mon avis.

Même problème en java ici : http://www.geogebra.org/forum/viewtopic.php?t=1350

J'ai déjà vu des calculatrices de grandes marques qui plantaient les résultats sur des additions de fractions simples.
Arnaud
Un peu d'info - Pyromaths - Pas d'aide en MP (non plus)
kojak
Modérateur général
Modérateur général
Messages : 10424
Inscription : samedi 18 novembre 2006, 19:50

Message non lu par kojak »

C'est encore plus rigolo quand tu changes la précision..... le résultat change....
Par défaut la précision serait à 16, si je comprends bien... Si tu la diminues, ça a l'air de coller...
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Message non lu par MB »

Arnaud a écrit :Erreur d'arrondis à mon avis.
Il me faudrait des détails sur l'algorithme utilisé pour effectuer une soustraction (de nombres décimaux) mais je me demande bien pourquoi il a besoin de faire des arrondis. D'autant que le nombre de décimales de ces décimaux est bien faible (bien inférieur au digit limite de Maxima en tout cas).
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
gigiair
Utilisateur chevronné
Utilisateur chevronné
Messages : 2676
Inscription : samedi 08 juillet 2006, 20:56
Localisation : Saint Bonnet Elvert

Message non lu par gigiair »

MB a écrit :
Arnaud a écrit :Erreur d'arrondis à mon avis.
Il me faudrait des détails sur l'algorithme utilisé pour effectuer une soustraction (de nombres décimaux) mais je me demande bien pourquoi il a besoin de faire des arrondis. D'autant que le nombre de décimales de ces décimaux est bien faible (bien inférieur au digit limite de Maxima en tout cas).
AMHA les calculs en interne sont en binaire. La perte de précision se fait à cause de la conversion décimal->binaire qui en général n'est pas exacte.
--
JJR.
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Message non lu par MB »

gigiair a écrit :AMHA les calculs en interne sont en binaire. La perte de précision se fait à cause de la conversion décimal->binaire qui en général n'est pas exacte.
De toute façon il y a bien un problème quelque part c'est sûr.
Mais les décimaux ne doivent pas spécialement être bien différents des entiers (couple d'entiers au pire). En tout cas, ça ne fait pas très sérieux, surtout pour un logiciel de calcul formel.

Sinon :

Code : Tout sélectionner

7.64-5.84;
donne bien
Mais :

Code : Tout sélectionner

8.64-6.84;
donne

Code : Tout sélectionner

1.800000000000001
Par contre, en forçant un peu l'usage des fractions :

Code : Tout sélectionner

float(864/100-684/100);
donne bien
Je pense que ce genre de bug pourrait être corrigé tout de même. :P
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
Arnaud
Modérateur honoraire
Modérateur honoraire
Messages : 7095
Inscription : lundi 28 août 2006, 13:18
Localisation : Allemagne

Message non lu par Arnaud »

Ce que dit gigiair est juste, est c'est à mon avis le problème le plus récurrent en info : la conversion dans un autre type de données.

Il y a certaines valeurs qui passent et d'autres non, pour des raisons qui m'échappent, et ça peut devenir un véritable casse-tête pour un programmeur de déceler l'origine d'une telle erreur.

En déclarant le type de données dans ton calcul, tu peux ainsi éviter les erreurs, mais ça devient vite lourd...
Arnaud
Un peu d'info - Pyromaths - Pas d'aide en MP (non plus)
gigiair
Utilisateur chevronné
Utilisateur chevronné
Messages : 2676
Inscription : samedi 08 juillet 2006, 20:56
Localisation : Saint Bonnet Elvert

Message non lu par gigiair »

Maxima ne calcule pas les valeurs en virgules flottantes. Il passe à Lisp et effectue la troncature correspondant à la précision demandée.
La valeur renvoyée par Lisp est 1.8000000000000007 ce qui est arrondi à 1.800000000000001 quand fpprec=16.
Je pense que Lisp code les flottants en binaire sur un nombre d'octets fixes, et je pense qu'il doit utiliser bêtement les bibliothèques C standard. Il faudrait demander à quelqu'un qui connaît, mais je ne trouve pas ça très intéressant. En tout cas, c'est sûr que ce n'est pas un bug.
Il est un peu illogique de demander à un calculateur symbolique de calculer en virgule flottante, puisque par définition ce calcul est approché.
Toutes les calculatrices (en virgules flottantes) ont un $\epsilon$ qui est la plus grande valeur telle que $1+\epsilon-1=0$.
Dans le cas de Maxima, on peut vérifier que
$$0.11102230246\times10^{-15}\leqslant\epsilon\leqslant0.11102230247\times10^{-15}$$
C'est de l'ordre de grandeur du $\epsilon$ des calculatrices de poche. On peut demander d'effectuer les calculs en bigfloat pour plus de précision, mais le problème subsistera toujours.
--
JJR
Arnaud
Modérateur honoraire
Modérateur honoraire
Messages : 7095
Inscription : lundi 28 août 2006, 13:18
Localisation : Allemagne

Message non lu par Arnaud »

C'est intéressant, mais je n'ai pas compris pourquoi l'erreur est présente pour $8.64-6.84$ et pas pour $7.64-5.84$.
Il est un peu illogique de demander à un calculateur symbolique de calculer en virgule flottante, puisque par définition ce calcul est approché.
Oui, tout à fait;
Sur le lien que je donne au-dessus, on a l'exemple d'un prof qui veut faire une activité avec ses élèves, basée sur le fait que le minimum d'une fonction est 21.
Erreur, le programme donne 20, c'est tout de même gênant pour une utilisation ultérieure de cette valeur et pour l'intégrité de l'exercice.
Bon tu me diras : geogebra n'est pas réellement un calculateur.
Arnaud
Un peu d'info - Pyromaths - Pas d'aide en MP (non plus)
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Message non lu par MB »

Tu as retrouver comment la valeur renvoyée par Lisp ? (d'où vient ce 7 ?)

Il est en effet fort possible que ce genre de problème vienne des bibliothèques génériques de C. Je signale que Maple ne fait pas cette erreur (ni même les calculatrices bas de gamme).

C'est peut être pas un bug, mais je pense que la méthode utilisée par Maxima pour ce genre de calculs n'est pas bonne. Il semble qu'il ferait mieux de ne pas faire appel à Lips.
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Message non lu par MB »

Pour une explication détaillée de la méthode d'addition (et de soustraction) en virgule flottante, cette page est bien faite.
En effet, c'est tout à fait approximatif, même pour des nombres qui ne nécessiteraient pas un arrondi.

D'après ce site, on devrait trouver $8.64-6.84=1.8000002$ et $7.64-5.84=1.7999997$.
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
Arnaud
Modérateur honoraire
Modérateur honoraire
Messages : 7095
Inscription : lundi 28 août 2006, 13:18
Localisation : Allemagne

Message non lu par Arnaud »

Ok, merci MB :wink:
Arnaud
Un peu d'info - Pyromaths - Pas d'aide en MP (non plus)
gigiair
Utilisateur chevronné
Utilisateur chevronné
Messages : 2676
Inscription : samedi 08 juillet 2006, 20:56
Localisation : Saint Bonnet Elvert

Message non lu par gigiair »

MB a écrit :Pour une explication détaillée de la méthode d'addition (et de soustraction) en virgule flottante, cette page est bien faite.
En effet, c'est tout à fait approximatif, même pour des nombres qui ne nécessiteraient pas un arrondi.

D'après ce site, on devrait trouver $8.64-6.84=1.8000002$ et $7.64-5.84=1.7999997$.
Maxima est programmé en clisp.
La représentation des nombres est beaucoup plus complexe en informatique qu'en mathématique.
voici celle de clisp:
http://fr.wikipedia.org/wiki/Common_Lisp#Nombres
le clisp de maxima a un type supplémentaire : bigfloat, flottants dont la précision est fixée par la valeur de fpprec
bfloat(x) convertit x en un bigfloat.
Pour saisir une constante en bigfloat, il suffit d'ajouter b suivi de l'exposant.
par exemple, 1 est un entier 1e0 ou 1d0 sont des float, 1b0 est un bigfloat.
Pour que le résultat de ton opération soit calculé en bigfloat, il aurait fallu taper
8.64b0-6.84b0;
1.8b0.
Ce qui est plutôt rassurant.

----------
en clisp,
(- 8.64s0 6.84s0) renvoie 1.79999s0 (type short -float)
(- 8.64e0 6.84e0) renvoie 1.8000002 (type single-float)
(- 8.64d0 6.84d0) renvoie 1.8000000000000007d0 (type double-float)
(- 8.64l0 6.84l0) renvoie 1.8000000000000000002L0 (type long-float)
gnu-clisp n'a pas de bigfloat par défaut
par défaut maxima représente les flottants en double-float.
------

Pour passer en clisp, évaluer sous maxima

Code : Tout sélectionner

to_lisp() ;
Puis pour revenir en mode maxima, évaluer

Code : Tout sélectionner

(to-maxima)
--
JJR.
MB
Administrateur
Administrateur
Messages : 7729
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Message non lu par MB »

Merci beaucoup pour ces précisions intéressantes.
gigiair a écrit :le clisp de maxima a un type supplémentaire : bigfloat, flottants dont la précision est fixée par la valeur de fpprec
Apparemment le type LONG-FLOAT est assez similaire. Je trouve ici :
Arbitrary Precision Floats. LONG-FLOATs have variable mantissa length, which is a multiple of 16 (or 32, depending on the word size of the processor). The default length used when LONG-FLOATs are READ is given by the place (EXT:LONG-FLOAT-DIGITS). It can be set by (SETF (EXT:LONG-FLOAT-DIGITS) n), where n is a positive INTEGER. E.g., (SETF (EXT:LONG-FLOAT-DIGITS) 3322) sets the default precision of LONG-FLOATs to about 1000 decimal digits.
Donc à part ça, une DOUBLE-FLOAT semble codé sur 64 bits : 1 (signe) + 52 (mantisse) + 11 (exposant). (voir ici pour la norme IEEE-754 que semble respecter Lisp (à peu près)).

Sur ce lien il était indiqué 52+1 bits pour la mantisse. Voici l'explication :
In describing binary floating-point types, the significand is characterized by a certain width in bits (binary digits). Because the most significant bit is always 1 for normal numbers, this bit is typically not stored and is called the "hidden bit". Depending on the context, the hidden bit may or may not be counted in describing the width of the significand. For example, the same IEEE 754 double precision format is commonly described either as having a 53-bit significand/mantissa (including the hidden bit) or as having a 52-bit significand/mantissa (not including the hidden bit).
Source : Wikipédia.

En tout cas, pour stocker le décimal $6,84$ dans une variable de type FLOAT, il faut commencer par l'écrire sous forme binaire mais avec la virgule. C'est à dire :

$$6,84 = \ds\sum_{k \in \Z} b_k \times 2^k $$

Par exemple, le décimal $2,625$ s'écrit $10,101$ en binaire. Pour calculer la partie décimale, on utilise une méthode par multiplication (voir ici):

Code : Tout sélectionner

0.625	×	2	=	1.25		1
0.25	×	2	=	0.5		0
0.5	×	2	=	1.0		1
Cette méthode ne se termine pas forcément. Ici elle se termine bien car $\dfrac{625}{1000}=\dfrac{5}{8}=\dfrac{5}{2^3}$.

Par contre, pour $6,84 = \dfrac{684}{100} = \dfrac{171}{25}= \dfrac{171}{5^2}$ la procédure ne se termine pas et on tombe forcément sur une approximation de $6,84$.
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
gigiair
Utilisateur chevronné
Utilisateur chevronné
Messages : 2676
Inscription : samedi 08 juillet 2006, 20:56
Localisation : Saint Bonnet Elvert

Message non lu par gigiair »

Bon, tout ça ce sont des bonnes nouvelles. Dommage que la doc de maxima soit aussi rébarbative, c'est vraiment un bon logiciel. On pourrait faire de belles économies en l'utilisant dans les classes prépas de préférence à un logiciel payant.
C'était une très bonne question. merci MB.
--
JJR.