MySQL -
Écrit par Durand Franck


Publié le 11.11.10
Une chose à savoir avec les valeurs à virgules flottantes est qu'elles sont stockées de manières approximatives et non pas exacte comme le reste des valeurs.
A première vue sa ne pose pas de problème, sur une requête simple les valeurs retournées sont les bonnes, mais les problèmes arrivent quand on demande à MySQL de faire des calculs ou des comparaisons sur ces valeurs.
Le simple fait de demander le résultat d'un calcul sur un flottant retournera sa valeur approximative, par exemple :
CREATE TABLE test (val FLOAT(10.2)); INSERT INTO test VALUES ("3.2"), ("4.1"); SELECT SUM(val) FROM test;
// retourne 7.29999995231628 au lieu de 7.2 attendu
Dans un cas simple comme celui la il suffit d'utiliser la fonction ROUND(x, y) avec y égal a la précision après la virgule souhaitée :
SELECT ROUND(SUM(val, 2)) FROM test; // retourne 7.2
Egalement en utilisant les résultats dans les clauses de la requête d'autre problèmes apparaissent. Prenons l'exemple suivant :
CREATE TABLE test2 (i INT, val1 FLOAT(10.2), val2 FLOAT(10.2)); INSERT INTO test2 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00); SELECT SUM(val1) AS a, SUM(val2) AS b FROM test2 GROUP BY i HAVING a <> b;
// retourne a=21.4000015258789, b=22.3999996185303
Même en utilisant la fonction ROUND(x, y) cela ne résoudrai pas le problème ( Note pour plus tard : dépend de l'architecture du processeur ), car la valeur résultante est également stocké de manière approximative en mémoire, et l'ont se retrouverai avec des valeur en apparence égale malgré la clause HAVING a <> b.
La seul solution acceptable est de définir un niveau de précision dans lequel s’effectueront les comparaisons :
SELECT SUM(val1) AS a, SUM(val2) AS b FROM test2 GROUPE BY i HAVING ABS(a - b) > 0.001;
// ne retourne rien
En fonction de l'architecture du processeur utilisé, les résultat présenté ici peuvent être différent de ceux que vous obtiendrez car il n'existe pas de règle strict quand au calcul à virgules flottantes pour les processeur. Il est ainsi souvent répondu de multiplier le résultat par 1 afin d'obtenir une valeur exacte au lieu d'une valeur approximative, mais ce n'est valable que sur certain processeur, et cette solution est donc a proscrire !
Egalement comprenez bien que même si votre serveur vous répond correctement quand je montre ici que la réponse n'est pas celle attendu, cela ne sera pas forcément vrai sur un autre serveur, il est donc important de mettre en oeuvre les concepts présenté dans cet article !