Arrondis avec MySQL et PHP

Ah les arrondis ! On pourrait penser que c'est très simple mais comme souvent le diable se cache dans les détails.

Prenons par exemple la méthode round de PHP. Elle nous propose 4 types d'arrondi :

<?php
// Arrondi vers l'infini (méthode par défaut: PHP_ROUND_HALF_UP)
echo round(1.2442) . "\n"// Affiche 1.24
echo round(1.2462) . "\n"// Affiche 1.25
echo round(1.2452) . "\n"// Affiche 1.25
echo round(-1.2452) . "\n"// Affiche -1.25

// Arrondi vers zéro
echo round(1.2452PHP_ROUND_HALF_DOWN) . "\n"// Affiche 1.24
echo round(-1.2452PHP_ROUND_HALF_DOWN) . "\n"// Affiche -1.24

// Arrondi bancaire (arrondi au nombre pair le plus proche)
echo round(1.2452PHP_ROUND_HALF_EVEN) . "\n"// Affiche 1.24
echo round(1.2352PHP_ROUND_HALF_EVEN) . "\n"// Affiche 1.24

// Arrondi au nombre impair le plus proche
echo round(1.2452PHP_ROUND_HALF_ODD) . "\n"// Affiche 1.25
echo round(1.2352PHP_ROUND_HALF_ODD) . "\n"// Affiche 1.23
?>

Les arrondis au chiffre impair ou pair le plus proche présentent l'avantage de répartir équitablement les erreurs.

Il y aussi les fonctions floor (plancher en anglais, arrondi à l'entier inférieur) et ceil (plafond en anglais, arrondi à l'entier supérieur) :

<?php
echo floor(1.5). "\n"// Affiche 1
echo floor(-1.5). "\n"// Affiche -2

echo ceil(1.5). "\n"// Affiche 2
echo ceil(-1.5). "\n"// Affiche -1
?>

Il faut donc sélectionner la bonne méthode en fonction de la situation. Pour les impôts en France, où on ne doit pas inscrire les centimes, on doit par exemple respecter la règle suivante :

La fraction d'euro égale à 0,50 est comptée pour 1.

Donc une somme de 1 000,50 € est arrondie à 1 001 €. On arrondi donc vers l'infini. Ca tombe bien, c'est la méthode par défaut de PHP. Mais quand est-il de MySQL ?

Et bien en fait, ça dépends de la bibliothèque C utilisée d'après la documentation :

Notez que le comportement de l'opérateur ROUND(), lorsque l'argument est exactement entre deux entiers, dépend de la bibliothèque C active. Certaines arrondissent toujours à l'entier pair le plus proche, toujours vers le haut, toujours vers le bas, ou toujours vers zéro.

Prenez donc le temps de tester votre serveur MySQL à l'aide d'une requête pour vous assurer que la méthode utilisée est bien la même que vous utilisez côté PHP :

-- Retourne 1.25, 1.24, -1.25 si MySQL arrondi vers l'infini
SELECT ROUND(1.245, 2), ROUND(1.235, 2), ROUND(-1.245, 2);

Sur un serveur 5.1.34 sur Windows, MySQL arrondi vers l'infini. Idem pour un 5.0.70 sous Linux. Si vous avez besoin d'utiliser une autre méthode, vous pouvez utiliser les astuces proposées dans les commentaires de la version anglaise de la documentation de MySQL.

Finalement, l'endroit où vous réalisez votre arrondi à son importance. Si on prend une facture comportant plusieurs lignes par exemple, il faut arrondir au centime le total de chaque ligne, puis additionner ces sous-totaux pour obtenir le montant total de la facture.

Si vous additionnez chaque total de ligne avec la précision maximale, puis réalisez la somme de ses sous-totaux, vous risquez d'avoir une incohérence :

2,1 mètres de tissu à 5,96 € le mètre : 26,292 € arrondi à 26,29 €
3,6 mètres de tissu à 7,24 € le mètre : 26,064 € arrondi à 26,06 € 
 
Total avec arrondi à la fin : 26,292 + 26,064 = 52,356 arrondi à 52,36 €
Total avec arrondi à chaque ligne : 26,29 + 26,06 = 52,35 €

Vous voyez, on a perdu un centime d'euro dans la bagarre. La deuxième méthode, bien que moins précise est la bonne car l'affichage va être cohérent.

Etiquettes:

Commentaires

Comme dit, Pour les impôts en France, où on ne doit pas inscrire les centimes. On ne doit pas néanmoins arrondir.
1000,50 comme 1000,99 s'écrit 1000.

Fait gaffe, ils vont débarquer chez toi pour te réclamer l'euro manquant ;-)

http://www.legifrance.gouv.fr/affichCode.do;jsessionid=108BDBE3EF24F6B89...

http://www.colloc.bercy.gouv.fr/colo_struct_fina_loca/tva/regl_darr.html

http://legifrance.gouv.fr/affichCodeArticle.do;jsessionid=B7901464F0ADE2...

On arrondi à l'euro le plus proche et la fraction égale à 0,50 est comptée comme 1 euro. Donc 1 000,99 € -> 1 001 € et 1000,50 € -> 1 001 €. Enfin, c'est que je comprend de leur charabia.

Ajouter un commentaire