Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#1 07/06/2010 11:36:03
- ced
- Membre
Curiosité sur la fonction SUM() avec nombres à virgule flottante
Bonjour,
Je suis en PostgreSQL 8.4.3 sous RedHat.
J'observe un comportement curieux quand je fais la somme sur une colonne de type REAL (nombre à virgule flottante sur 4 octets).
En effet, si je fais la requête suivante :
SELECT SUM(macolonne1) AS total_colonne1 FROM matable
J'obtiens le total suivant : 275375
Si je décompose ensuite selon une seconde colonne, par la requête suivante :
SELECT macolonne2, SUM(macolonne1) AS total_colonne1 FROM matable GROUP BY macolonne2
J'obtiens le résultat suivant :
macolonne2 total_colonne1
0 54754,8
1 54601,1
2 55598,3
3 55248
4 55178
dont le total fait 275380,2.
Enfin, si j'exécute la requête suivante, en typant ma colonne explicitement :
SELECT SUM(macolonne1::float) AS total_colonne1 FROM matable
J'obtiens un total de 275381,66...
Quand j'exporte toutes mes lignes dans un outil permettant de faire la somme sur la colonne 1 (logiciel R), le total que m'affiche cet outil est 275381,66.
Bref, je suis surpris d'observer de tels écarts. A quoi cela peut-il être dû ?
Et surtout, que dois-je faire dans mes différentes requêtes qui utilisent des sommes (ou autres fonctions d'agrégations) pour être certain que mes totaux soient le plus juste possible ? Faut-il systématiquement caster explicitement ?
Merci de votre aide,
ced
Dernière modification par ced (07/06/2010 12:20:04)
Hors ligne
#2 07/06/2010 14:00:49
- Marc Cousin
- Membre
Re : Curiosité sur la fonction SUM() avec nombres à virgule flottante
Cela est du à des erreurs d'arrondis (les float et double utilisent une notation mantisse/exposant). Si vous voulez travailler avec des résultats exacts, utilisez les formats numeric. Sachez par contre qu'ils sont plus lents.
Pour reprendre :
SELECT SUM(macolonne1) AS total_colonne1 FROM matable : vous faites des sommes de 'real', c'est à dire de nombres simple précision.
SELECT macolonne2, SUM(macolonne1) AS total_colonne1 FROM matable GROUP BY macolonne2, vous faites des sommes de real, recevez un résultat arrondi, que vous sommez ensuite à la main.
SELECT SUM(macolonne1::float) AS total_colonne1 FROM matable : vous convertissez vos simple précision en double précision, puis faites une somme double précision.
Marc.
Hors ligne
#3 07/06/2010 15:25:26
- ced
- Membre
Re : Curiosité sur la fonction SUM() avec nombres à virgule flottante
Merci pour ces éléments de réponse.
La première requête me laisse tout de même perplexe : pourquoi une somme sur un nombre stocké en real entraîne un tel écart de total au final (plusieurs unités) ?
Quand on regarde la documentation de PostgreSQL, il est précisé que le type real a une précision d'au moins 6 chiffres décimaux.
Sachant que ma table contient 250000 lignes, je devrais avoir un erreur de l'ordre de 0,25 et pas de plusieurs unités ?
ced
Dernière modification par ced (07/06/2010 15:31:32)
Hors ligne
#4 07/06/2010 15:47:30
- Marc Cousin
- Membre
Re : Curiosité sur la fonction SUM() avec nombres à virgule flottante
La précision est de 6 chiffres sur le real. En tout, pas après la virgule. C'est la taille de la «mantisse».
Marc.
Hors ligne