je crois c'est plutôt un problème de représentation/stockage des nombres en virgule flottante en SQL (peut-être à cause de la nature binaire des principaux composants informatiques)
Oui, c'est ça, mais c'est pas limité au SQL, on a le même problème avec les floats/doubles dans n'importe quel langage de programmation qui les gère.
Comment est stocké un float (ou double, peu importe) en mémoire ? On a 3 éléments : une mantisse, un exposant et un signe. La mantisse et l'exposant sont des nombres entiers, le signe est juste un bit. La valeur représentée sera calculée comme mantisse\times{}2^{exposant} puis suivant le bit de signe, ça sera positif ou négatif. Le problème de ceci, c'est que l'exposant est appliqué en base 2, ce qui empêche de représenter de façon exacte certains nombres. Par exemple, on peut représenter sans problème 0.5 (2-1), mais 0.1 n'a pas de représentation exacte en float. C'est exactement le même problème qu'en décimal pour représenter des nombres comme 1/3 ou 1/7, on doit se contenter d'une approximation.
Pour un type decimal ou monétaire, c'est exactement le même principe, on retrouve nos mantisse, exposant et signe, mais la différence est que l'exposant est appliqué en base 10. Du coup, tout nombre avec un développement décimal fini est représentable de façon exacte (tant qu'on reste dans les bornes admises par le type).
Le problème quand on manipule des données monétaires avec des floats, c'est que pratiquement chaque valeur non entière sera entachée d'une petite erreur dès le départ, et que ces erreurs vont pouvoir s'accumuler au fil des calculs, et on risque d'avoir un résultat significativement faux à la fin.
[^] # Re: nan, c'est pas un problème d'arrondi qui te guette
Posté par Buf (Mastodon) . En réponse au journal SQL Decimal vs Double. Évalué à 7.
Oui, c'est ça, mais c'est pas limité au SQL, on a le même problème avec les floats/doubles dans n'importe quel langage de programmation qui les gère.
Comment est stocké un float (ou double, peu importe) en mémoire ? On a 3 éléments : une mantisse, un exposant et un signe. La mantisse et l'exposant sont des nombres entiers, le signe est juste un bit. La valeur représentée sera calculée comme mantisse\times{}2^{exposant} puis suivant le bit de signe, ça sera positif ou négatif. Le problème de ceci, c'est que l'exposant est appliqué en base 2, ce qui empêche de représenter de façon exacte certains nombres. Par exemple, on peut représenter sans problème 0.5 (2-1), mais 0.1 n'a pas de représentation exacte en float. C'est exactement le même problème qu'en décimal pour représenter des nombres comme 1/3 ou 1/7, on doit se contenter d'une approximation.
Pour un type decimal ou monétaire, c'est exactement le même principe, on retrouve nos mantisse, exposant et signe, mais la différence est que l'exposant est appliqué en base 10. Du coup, tout nombre avec un développement décimal fini est représentable de façon exacte (tant qu'on reste dans les bornes admises par le type).
Le problème quand on manipule des données monétaires avec des floats, c'est que pratiquement chaque valeur non entière sera entachée d'une petite erreur dès le départ, et que ces erreurs vont pouvoir s'accumuler au fil des calculs, et on risque d'avoir un résultat significativement faux à la fin.