Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème de Float ?

10 réponses
Avatar
Sylvain
Bonjour =E0 tous,

Voil=E0, je rencontre un probl=E8me ennuyeux en ce moment avec
l'utilisation des float dans python lorsque je convertis des chiffres
initialement au format =AB string =BB (r=E9cup=E9r=E9s dans un fichier
texte) et que je les convertis en float pour entamer une =E9tape de
calculs : python semble convertir les chiffres qui lui sont fournis
en arrondis hasardeux.

Exemple : 51.3 deviendra 51.299999999999997 (lorsqu'il est inscrit
dans une liste) ou 51.3000000000000001 alors qu'il affichera bien
51.3 sur la console si on lui demande la valeur existante dans
ma_liste[128] par exemple.

A la rigueur, =E7=E0 ne pose pas trop de probl=E8mes si on se base sur 1
chiffre significatif et qu'on r=E9sout des =AB op=E9rations simples =BB
sur peu de valeurs. Cependant =E7=E0 deviens vite critique qu'on traite
=E0 l'inverse beaucoup de donn=E9es et des calculs plus =AB complexes =BB
(carr=E9s, exponentielles, proba, etc.) J'ai fais des tests m=EAme sur
des choses toutes b=EAtes comme les moyenne !

Exemple :

#---------------------------------------------------------------------------
import os, sys, string, re, math

#on cree un fichier avec des valeurs, peu importe...
fic=3Dopen('mon_fichier.txt','w')
for x in range(0,50000):
v=3D(x+1.2)/math.sqrt((x+1.2)/9)
fic.write(str(round((x+1.2)/math.sqrt((x+1.2)/9),1))+'\n')
fic.close()

#une fonction pour obtenir la moyenne
def moyenne(liste):
somme=3D0
for element in liste[:-1]:
element=3Dfloat(element)
somme+=3Delement
return somme/len(liste)

#on recupere dans une liste tous les nombres du fichier
def scan(fic):
tab=3D[]
fic=3Dopen(fic,"r")
while 1:
line=3Dfic.readline()
tab.append(line[:-1])
if not line:
break
fic.close()
return tab

tab=3Dscan('mon_fichier.txt')
print moyenne(tab)

#---------------------------------------------------------------------------

Python donne pour moyenne la valeur suivante : 447.214
R (logiciel statistique) donne la valeur suivante : 447.223
Excel.... Donne la m=EAme valeur : 447.223

Est-ce qu'il s'agit d'un vrai probl=E8me ?
Est-ce que =E7=E0 veux dire qu'on ne peux pas vraiment faire de calculs
scientifiques avec python ?
ou bien ai-je loup=E9 un =E9pisode ?

Help !!!

Merci d'avance.

Sylvain

10 réponses

Avatar
rafi
Sylvain wrote:
Bonjour à tous,


bonjour

Est-ce qu'il s'agit d'un vrai problème ?
Est-ce que çà veux dire qu'on ne peux pas vraiment faire de calculs
scientifiques avec python ?
ou bien ai-je loupé un épisode ?


les floats sont des floats, c'est à dire des valeurs arondies par
rapport à une représentation informatisée

utiliser le package décimal est peut ête la solution à ton problème (que
je n'ai jamais utilisé)

mes 2 cents

--
rafi

"Imagination is more important than knowledge."
(Albert Einstein)

Avatar
Sylvain
les floats sont des floats, c'est à dire des valeurs arondies par
rapport à une représentation informatisée


C'est vrai, mais çà n'explique pas totalementles différences de
calcul observées :

1- Quand on passe directement des float générés par python en
arguments de la fonction moyenne, j'obtiens la moyenne de ~447,210.

2- Quand je fais exactement le même calcul cette fois-ci en
récupérant les valeurs float dans un fichier texte, la moyenne est de
: ~447,214

Pourquoi d'autres logiciels eux aussi gérant les mêmes arrondis (avec
du langage comme du c ou du c++ derrière), ne font pas les mêmes
erreurs d'approximation (moyD7,223) ?

utiliser le package décimal est peut ête la solution à ton problè me (que
je n'ai jamais utilisé)


Ce serait pas mal... Je vais y jetter un coup d'oeil.
Merci :)

Avatar
Paul Gaborit
À (at) 28 Jul 2005 10:36:26 -0700,
"Sylvain" écrivait (wrote):
[...]
#on recupere dans une liste tous les nombres du fichier
def scan(fic):
tab=[]
fic=open(fic,"r")
while 1:
line=fic.readline()
tab.append(line[:-1])
if not line:
break
fic.close()
[...]

ou bien ai-je loupé un épisode ?


50000 != 50001 !!!

Votre test de fin de fichier devrait être avant le 'append'...

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>

Avatar
rafi
Sylvain wrote:
les floats sont des floats, c'est à dire des valeurs arondies par
rapport à une représentation informatisée
C'est vrai, mais çà n'explique pas totalementles différences de

calcul observées :

1- Quand on passe directement des float générés par python en
arguments de la fonction moyenne, j'obtiens la moyenne de ~447,210.

2- Quand je fais exactement le même calcul cette fois-ci en
récupérant les valeurs float dans un fichier texte, la moyenne est de
: ~447,214


une explication potentielle: le float est un arrondi dont l'affichage
est aussi un arrondi. donc lorsqu'on le stocke dans un fichier on doit
faire une approximation de la valeur mémoire et donc "on perd un peu de
la valeur des nombres". cela ne me surprends donc pas que le passage par
un fichier texte implique des problèmes de calcul. il faudrait peut être
mieux sauvegarder les nombres dans un fichier binaire?

Pourquoi d'autres logiciels eux aussi gérant les mêmes arrondis (avec
du langage comme du c ou du c++ derrière), ne font pas les mêmes
erreurs d'approximation (moyD7,223) ?


je ne sais as

Merci :)


avec plaisir

mes derniers 2 cents

--
rafi

"Imagination is more important than knowledge."
(Albert Einstein)


Avatar
Hervé Cauwelier
Pourquoi d'autres logiciels eux aussi gérant les mêmes arrondis (avec
du langage comme du c ou du c++ derrière), ne font pas les mêmes
erreurs d'approximation (moyD7,223) ?


Parce qu'ils savent que les fonctions standard sont trop approximatives
et implémentent les leurs, comme le fait le nouveau module decimal.

Cette question revient tellement souvent que je doute que tu ais
cherché. Le grand classique est les gens qui demandent pourquoi Python
calcul faux. C'était un titre de FAQ, de mémoire.

http://python.org/doc/2.4/whatsnew/node9.html

--
Hervé Cauwelier
http://www.oursours.net/

Avatar
Paul Gaborit
À (at) Fri, 29 Jul 2005 13:08:42 +0200,
Hervé Cauwelier écrivait (wrote):
Parce qu'ils savent que les fonctions standard sont trop
approximatives et implémentent les leurs, comme le fait le nouveau
module decimal.


Les erreurs d'arrondis n'expliquent pas tout... En tous cas pas une
erreur aussi importante ;-)

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>

Avatar
JBB
Bonjour à tous,

Voilà, je rencontre un problème ennuyeux en ce moment avec
l'utilisation des float dans python lorsque je convertis des chiffres
initialement au format « string » (récupérés dans un fichier
texte) et que je les convertis en float pour entamer une étape de
calculs : python semble convertir les chiffres qui lui sont fournis
en arrondis hasardeux.

Exemple : 51.3 deviendra 51.299999999999997 (lorsqu'il est inscrit
dans une liste) ou 51.3000000000000001 alors qu'il affichera bien
51.3 sur la console si on lui demande la valeur existante dans
ma_liste[128] par exemple.

Ca c'est le probleme des float. Il y a quasiment systematiquement une

approximation.
Mais d'ailleurs ce n'est pas forcement un probleme. Dans la 'vraie' vie
un float est toujours une aproximation. Si je dis que je pese 65 kg
c'est une approximation, je pese surement 65,xxxxxxxxxxxxxxxxxxxxxxx....
kg. Et si je fais 7km tous les matins il manque aussi des chiffres apres
la virgule.


A la rigueur, çà ne pose pas trop de problèmes si on se base sur 1
chiffre significatif et qu'on résout des « opérations simples »
sur peu de valeurs. Cependant çà deviens vite critique qu'on traite
à l'inverse beaucoup de données et des calculs plus « complexes »
(carrés, exponentielles, proba, etc.) J'ai fais des tests même sur
des choses toutes bêtes comme les moyenne !

Exemple :

#---------------------------------------------------------------------------
import os, sys, string, re, math

#on cree un fichier avec des valeurs, peu importe...
fic=open('mon_fichier.txt','w')
for x in range(0,50000):
v=(x+1.2)/math.sqrt((x+1.2)/9)
fic.write(str(round((x+1.2)/math.sqrt((x+1.2)/9),1))+'n')
fic.close()

J'ai executé ton exemple.

#une fonction pour obtenir la moyenne
def moyenne(liste):
somme=0
for element in liste[:-1]:
element=float(element)
somme+=element
print len(liste)

return somme/len(liste)

et là au surprise 'liste' contient 50001 elements: les 50000 valeurs

plus une chaine vide (la ligne vide en fin de fichier, probablement
rajoutée par fic.close() ).

Comme la fonction float renvoie 0 pour la chaine vide, la somme est
bonne , mais le diviseur est mauvais. Si tu divise par 50000 tu trouve
la bonne valeur ( 447.222962) .

Il n'y a donc pas de miracle ou d'erreur de python. L'erreur vient de toi.
Les float sont ce qu'ils sont, mais marchent tres bien pour ce pourquoi
ils sont faits.

#on recupere dans une liste tous les nombres du fichier
def scan(fic):
tab=[]
fic=open(fic,"r")
while 1:
line=fic.readline()
tab.append(line[:-1])
if not line:
break
fic.close()
return tab

tab=scan('mon_fichier.txt')
print moyenne(tab)

#---------------------------------------------------------------------------

Python donne pour moyenne la valeur suivante : 447.214
R (logiciel statistique) donne la valeur suivante : 447.223
Excel.... Donne la même valeur : 447.223

Est-ce qu'il s'agit d'un vrai problème ?
Est-ce que çà veux dire qu'on ne peux pas vraiment faire de calculs
scientifiques avec python ?
ou bien ai-je loupé un épisode ?

Help !!!

Merci d'avance.

Sylvain



Avatar
bug
Oui, il y a un problème dans ta boucle, voici la procédure scan
réécrite (plus pythonesque) :

def scan(fic):
fic=open(fic,"r")
tab=[ line[:-1] for line in fic.readlines()]
fic.close()
return tab

et sinon il y a aussi un problème dans ta fonction moyenne, tu ne
prends pas tout le monde (surement pour éviter le pb de la fonction
scan)

def moyenne(liste):
somme=0
for element in liste:
element=float(element)
somme+=element
return somme/len(liste)

Résultat : 447.222962 comme dans Excel !
Avatar
JBB

Bonjour à tous,

Voilà, je rencontre un problème ennuyeux en ce moment avec
l'utilisation des float dans python lorsque je convertis des chiffres
initialement au format « string » (récupérés dans un fichier
texte) et que je les convertis en float pour entamer une étape de
calculs : python semble convertir les chiffres qui lui sont fournis
en arrondis hasardeux.

Exemple : 51.3 deviendra 51.299999999999997 (lorsqu'il est inscrit
dans une liste) ou 51.3000000000000001 alors qu'il affichera bien
51.3 sur la console si on lui demande la valeur existante dans
ma_liste[128] par exemple.

Ca c'est le probleme des float. Il y a quasiment systematiquement une

approximation.
Mais d'ailleurs ce n'est pas forcement un probleme. Dans la 'vraie' vie
un float est toujours une aproximation. Si je dis que je pese 65 kg
c'est une approximation, je pese surement 65,xxxxxxxxxxxxxxxxxxxxxxx....
kg. Et si je fais 7km tous les matins il manque aussi des chiffres apres
la virgule.


A la rigueur, çà ne pose pas trop de problèmes si on se base sur 1
chiffre significatif et qu'on résout des « opérations simples »
sur peu de valeurs. Cependant çà deviens vite critique qu'on traite
à l'inverse beaucoup de données et des calculs plus « complexes »
(carrés, exponentielles, proba, etc.) J'ai fais des tests même sur
des choses toutes bêtes comme les moyenne !

Exemple :

#---------------------------------------------------------------------------

import os, sys, string, re, math

#on cree un fichier avec des valeurs, peu importe...
fic=open('mon_fichier.txt','w')
for x in range(0,50000):
v=(x+1.2)/math.sqrt((x+1.2)/9)
fic.write(str(round((x+1.2)/math.sqrt((x+1.2)/9),1))+'n')
fic.close()

J'ai executé ton exemple.


#une fonction pour obtenir la moyenne
def moyenne(liste):
somme=0
for element in liste[:-1]:
element=float(element)
somme+=element


print len(liste)

return somme/len(liste)

et là au surprise 'liste' contient 50001 elements: les 50000 valeurs

plus une chaine vide (la ligne vide en fin de fichier, probablement
rajoutée par fic.close() ).
Effectivement comme l'a dit Paulc'est à cause du append avant le break .


Comme la fonction float renvoie 0 pour la chaine vide, la somme est
bonne , mais le diviseur est mauvais. Si tu divise par 50000 tu trouve
la bonne valeur ( 447.222962) .

Il n'y a donc pas de miracle ou d'erreur de python. L'erreur vient de toi.
Les float sont ce qu'ils sont, mais marchent tres bien pour ce pourquoi
ils sont faits.

#on recupere dans une liste tous les nombres du fichier
def scan(fic):
tab=[]
fic=open(fic,"r")
while 1:
line=fic.readline()
tab.append(line[:-1])
if not line:
break
fic.close()
return tab

tab=scan('mon_fichier.txt')
print moyenne(tab)

#---------------------------------------------------------------------------


Python donne pour moyenne la valeur suivante : 447.214
R (logiciel statistique) donne la valeur suivante : 447.223
Excel.... Donne la même valeur : 447.223

Est-ce qu'il s'agit d'un vrai problème ?
Est-ce que çà veux dire qu'on ne peux pas vraiment faire de calculs
scientifiques avec python ?
ou bien ai-je loupé un épisode ?

Help !!!

Merci d'avance.

Sylvain





Avatar
JBB
Oui, il y a un problème dans ta boucle, voici la procédure scan
réécrite (plus pythonesque) :

def scan(fic):
fic=open(fic,"r")
tab=[ line[:-1] for line in fic.readlines()]
fic.close()
return tab

ou alors


def scan(fic):
tab=[ float(line) for line in open(fic,"r") if len(string.strip(line))>0]
return tab

et tu as directement un tableau de float avec tous les lignes vides filtrées


et sinon il y a aussi un problème dans ta fonction moyenne, tu ne
prends pas tout le monde (surement pour éviter le pb de la fonction
scan)

def moyenne(liste):
somme=0
for element in liste:
element=float(element)
somme+=element
return somme/len(liste)

Résultat : 447.222962 comme dans Excel !