Vous n'êtes pas identifié(e).

#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

Pied de page des forums