Différence entre le type de données float et decimal

Quelle différence cela fait-il lorsque j’utilise des types de données float et decimal dans MySQL?.

Quand devrais-je utiliser lequel?

C’est ce que j’ai trouvé quand j’ai eu ce doute.

 mysql> create table numbers (a decimal(10,2), b float); mysql> insert into numbers values (100, 100); mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G *************************** 1. row *************************** @a := (a/3): 33.333333333 @b := (b/3): 33.333333333333 @a + @a + @a: 99.999999999000000000000000000000 @b + @b + @b: 100 

La décimale a fait exactement ce qui était censé faire dans ces cas, elle a tronqué le rest, perdant ainsi la partie 1/3.

Donc, pour les sums, la décimale est meilleure, mais pour les divisions, le flottant est meilleur, jusqu’à un certain point, bien sûr. Je veux dire, utiliser DECIMAL ne vous donnera pas une “arithmétique à l’épreuve des échecs”.

J’espère que cela t’aides.

Un “float” dans la plupart des environnements est un type à virgule flottante binary. Il peut stocker avec précision les valeurs de base 2 (jusqu’à un certain point), mais ne peut pas stocker avec précision de nombreuses valeurs de base 10 (décimales). Les flotteurs sont les plus appropriés pour les calculs scientifiques. Ils ne sont pas adaptés à la plupart des mathématiques orientées métier, et une utilisation inappropriée des flotteurs vous piquerait. De nombreuses valeurs décimales ne peuvent pas être exactement représentées en base-2. 0.1 ne peut pas, par exemple, et vous voyez des résultats étranges comme 1.0 - 0.1 = 0.8999999 .

Les nombres décimaux stockent les nombres de base 10. Decimal est un bon type pour la plupart des mathématiques métier (mais tout type “money” intégré est plus approprié pour les calculs financiers), où la plage de valeurs dépasse celle fournie par les types entiers et les valeurs fractionnaires sont nécessaires. Les décimales, comme leur nom l’indique, sont conçues pour les nombres de base 10 – elles peuvent stocker avec précision les valeurs décimales (encore une fois, jusqu’à un certain point).

MySQL a récemment changé sa façon de stocker le type DECIMAL . Dans le passé, ils stockaient les caractères (ou les nybbles) pour chaque chiffre comprenant une représentation ASCII (ou nybble) d’un nombre – vs – un nombre entier de complément à deux, ou un dérivé de celui-ci.

Le format de stockage actuel de DECIMAL est une série d’entiers de 1,2,3 ou 4 octets dont les bits sont concaténés pour créer un nombre à deux compléments avec un point décimal implicite, défini par vous et stocké dans le schéma de firebase database lorsque vous déclarez la colonne et spécifiez sa taille DECIMAL et la position du point décimal.

À titre d’exemple, si vous utilisez un int 32 bits, vous pouvez stocker n’importe quel nombre compris entre 0 et 4 294 967 295. Cela ne couvrira de manière fiable que 999 999 999, donc si vous jetiez 2 bits et que vous l’utilisiez (1 << 30 -1), vous n'abandonneriez rien. La couverture de tous les numéros à 9 chiffres avec seulement 4 octets est plus efficace que la couverture de 4 chiffres en 32 bits en utilisant 4 caractères ASCII, ou 8 chiffres nybble. (un nybble est de 4 bits, permettant des valeurs de 0 à 15, plus que nécessaire pour 0 à 9, mais vous ne pouvez pas éliminer ce gaspillage en allant sur 3 bits, car cela ne couvre que les valeurs 0 à 7)

L’exemple utilisé sur les documents en ligne MySQL utilise DECIMAL (18,9) comme exemple. Il s’agit de 9 chiffres avant et de 9 chiffres derrière le point décimal implicite, ce qui, comme expliqué ci-dessus, nécessite le stockage suivant.

Comme 18 caractères 8 bits: 144 bits

As 18 nybbles 4 bits: 72 bits

Comme 2 entiers de 32 bits: 64 bits

Actuellement, DECIMAL supporte un maximum de 65 chiffres, comme DECIMAL (M, D) où la plus grande valeur pour M autorisée est 65, et la plus grande valeur de D autorisée est 30.

Afin de ne pas exiger des morceaux de 9 chiffres à la fois, des entiers inférieurs à 32 bits sont utilisés pour append des chiffres à l’aide d’entiers de 1,2 et 3 octets. Pour une raison quelconque qui défie la logique, signée, au lieu de ints non signés ont été utilisés, et ce faisant, 1 bit est jeté, entraînant les capacités de stockage suivantes. Pour les octets de 1,2 et 4 octets, le bit perdu n’a pas d’importance, mais pour les trois octets, c’est un désastre, car un chiffre entier est perdu à cause de la perte de ce bit.

Avec un int 7 bits: 0 – 99

Avec un int 15 bits: 0 – 9 999

Avec un int 23 bits: 0 – 999 999 (0 – 9 999 999 avec un int 24 bits)

Les entiers de 1,2,3 et de 4 octets sont concaténés pour former un “pool de bits” que DECIMAL utilise pour représenter le nombre avec précision comme un entier à complément à deux. Le point décimal n’est pas stocké, il est implicite.

Cela signifie que le moteur de firebase database ne requirejs aucune conversion ASCII vers int pour convertir le “numéro” en un nombre reconnu par la CPU. Pas d’arrondi, pas d’erreurs de conversion, c’est un nombre réel que le processeur peut manipuler.

Les calculs sur cet entier arbitrairement grand doivent être faits dans le logiciel, car il n’y a pas de support matériel pour ce type de nombre, mais ces bibliothèques sont très anciennes et hautement optimisées, écrit il y a 50 ans pour supporter des données à virgule flottante de précision arbitraire IBM 370 . Ils sont encore beaucoup plus lents que les algèbres entières de taille fixe effectuées avec un matériel entier de processeur, ou des calculs en virgule flottante effectués sur le FPU.

En termes d’efficacité du stockage, l’exposant d’un flottant étant associé à chaque flottant, en spécifiant implicitement où se trouve le point décimal, il est extrêmement redondant et donc inefficace pour le travail de la firebase database. Dans une firebase database, vous savez déjà où le point décimal doit être placé en avant, et chaque ligne de la table qui a une valeur pour une colonne DECIMAL doit uniquement regarder la spécification 1 & only indiquant où placer ce point décimal dans le schéma comme les arguments à un DECIMAL (M, D) comme l’implication des valeurs M et D.

Les nombreuses remarques trouvées ici sur le format à utiliser pour différents types d’applications sont correctes, alors je n’insisterai pas sur ce point. J’ai pris le temps d’écrire ceci parce que ceux qui conservent la documentation MySQL en ligne liée ne comprennent rien de ce qui précède et après des tentatives de plus en plus frustrantes pour les expliquer, j’ai abandonné. La présentation très confuse et presque indéchiffrable du sujet est une bonne indication de leur mauvaise compréhension.

En guise de conclusion, si vous avez besoin de calcul à virgule flottante de haute précision, il y a eu des progrès considérables dans le code à virgule flottante au cours des 20 dernières années, et la prise en charge matérielle des flotteurs à 96 bits et à quadruple précision mais il existe de bonnes bibliothèques de précision arbitraires si la manipulation de la valeur stockée est importante.

Non seulement spécifique à MySQL, la différence entre les types float et decimal est la manière dont ils représentent des valeurs fractionnaires. Les types à virgule flottante représentent des fractions en binary, qui ne peuvent représenter que des valeurs telles que {m*2^n | m, n Integers} {m*2^n | m, n Integers} . des valeurs telles que 1/5 ne peuvent pas être représentées avec précision (sans erreur d’arrondi). Les nombres décimaux sont pareillement limités, mais représentent des nombres comme {m*10^n | m, n Integers} {m*10^n | m, n Integers} . Les nombres décimaux ne peuvent toujours pas représenter des nombres comme 1/3, mais c’est souvent le cas dans de nombreux domaines communs, comme la finance, où l’on s’attend à ce que certaines fractions décimales puissent toujours être exprimées sans perte de fidélité. Un nombre décimal pouvant représenter une valeur comme $0.20 (un cinquième de dollar), il est préférable dans ces situations.

décimal est pour les quantités fixes comme l’argent où vous voulez un nombre spécifique de décimales. Les flotteurs servent à stocker … des nombres de précision à virgule flottante.

 mysql> CREATE TABLE num(id int ,fl float,dc dec(5,2)); Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO num VALUES(1,13.75,13.75); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO num VALUES(2,13.15,13.15); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM num WHERE fl = 13.15; Empty set (0.00 sec) mysql> SELECT * FROM num WHERE dc = 13.15; +------+-------+-------+ | id | fl | dc | +------+-------+-------+ | 2 | 13.15 | 13.15 | +------+-------+-------+ 1 row in set (0.00 sec) mysql> SELECT SUM(fl) ,SUM(dc) FROM num; +--------------------+---------+ | SUM(fl) | SUM(dc) | +--------------------+---------+ | 26.899999618530273 | 26.90 | +--------------------+---------+ 1 row in set (0.00 sec) mysql> SELECT * FROM num WHERE ABS(fl - 13.15)<0.01; +------+-------+-------+ | id | fl | dc | +------+-------+-------+ | 2 | 13.15 | 13.15 | +------+-------+-------+ 1 row in set (0.00 sec) 

Flotte:

Un petit nombre à virgule flottante (simple précision). Les valeurs admissibles sont les suivantes: -3,402823466E + 38 à -1,175494351E-38,0 et 1,175494351E-38 à 3,402823466E + 38. Ce sont les limites théoriques, basées sur la norme IEEE. La scope réelle peut être légèrement inférieure en fonction de votre matériel ou de votre système d’exploitation.

DÉCIMAL:

Un nombre à virgule fixe «exacte». M est le nombre total de chiffres (la précision) et D est le nombre de chiffres après la virgule (l’échelle). Le point décimal et (pour les nombres négatifs) le signe «-» ne sont pas comptabilisés dans inM. Si D est 0, les valeurs n’ont pas de point décimal ni de partie fractionnaire. Le nombre maximal de chiffres (M) pour DECIMAL est 65. Le nombre maximal de décimales sockets en charge (D) est 30. Si D est omis, la valeur par défaut est 0. Si M est omis, la valeur par défaut est 10.

J’ai trouvé cela utile:

Généralement, les valeurs flottantes sont bonnes pour les calculs scientifiques, mais ne doivent pas être utilisées pour les valeurs financières / monétaires. Pour les mathématiques orientées métier, utilisez toujours Decimal.

Source: http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/

Si vous recherchez des performances et non de la précision, notez que les calculs avec des flottants sont beaucoup plus rapides que les décimales.

Types à virgule flottante (valeur approximative) – FLOTTANT, DOUBLE

Les types FLOAT et DOUBLE représentent des valeurs de données numériques approximatives . MySQL utilise quatre octets pour des valeurs à simple précision et huit octets pour des valeurs à double précision.

Pour FLOAT, le standard SQL autorise une spécification facultative de la précision (mais pas de la plage de l’exposant) en bits après le mot-clé FLOAT entre parenthèses. MySQL prend également en charge cette spécification de précision facultative, mais la valeur de précision est utilisée uniquement pour déterminer la taille du stockage. Une précision de 0 à 23 donne une colonne FLOAT simple précision de 4 octets. Une précision de 24 à 53 donne une colonne DOUBLE à double précision de 8 octets.

MySQL autorise une syntaxe non standard: FLOAT (M, D) ou REAL (M, D) ou DOUBLE PRECISION (M, D). Ici, «(M, D)» signifie que les valeurs peuvent être stockées avec un total de M chiffres au maximum, dont D chiffres peuvent être après le point décimal. Par exemple, une colonne définie comme FLOAT (7,4) ressemblera à -999,9999 lorsqu’elle sera affichée. MySQL effectue un arrondi lors du stockage des valeurs, donc si vous insérez 999.00009 dans une colonne FLOAT (7,4), le résultat approximatif est 999 0001.

Étant donné que les valeurs à virgule flottante sont approximatives et ne sont pas stockées en tant que valeurs exactes, les tentatives de les traiter comme exactes dans les comparaisons peuvent entraîner des problèmes. Ils sont également soumis à des dépendances de plate-forme ou d’implémentation.

Pour une portabilité maximale, le code nécessitant le stockage de valeurs de données numériques approximatives doit utiliser FLOAT ou DOUBLE PRECISION sans spécification de précision ou de nombre de chiffres.

https://dev.mysql.com/doc/refman/5.5/fr/floating-point-types.html

Problèmes avec les valeurs à virgule flottante

Les nombres à virgule flottante sont parfois source de confusion car ils sont approximatifs et ne sont pas stockés comme des valeurs exactes . Une valeur à virgule flottante telle qu’écrite dans une instruction SQL peut ne pas être identique à la valeur représentée en interne. Les tentatives pour traiter les valeurs à virgule flottante comme exactes dans les comparaisons peuvent entraîner des problèmes. Ils sont également soumis à des dépendances de plate-forme ou d’implémentation. Les types de données FLOAT et DOUBLE sont sujets à ces problèmes. Pour les colonnes DECIMAL, MySQL effectue des opérations avec une précision de 65 chiffres décimaux, ce qui devrait résoudre les problèmes d’imprécision les plus courants.

L’exemple suivant utilise DOUBLE pour montrer comment les calculs effectués à l’aide d’opérations à virgule flottante sont soumis à une erreur en virgule flottante.

 mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE); mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), -> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40), -> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00), -> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00), -> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20), -> (6, 0.00, 0.00), (6, -51.40, 0.00); mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b -> FROM t1 GROUP BY i HAVING a <> b; +------+-------+------+ | i | a | b | +------+-------+------+ | 1 | 21.4 | 21.4 | | 2 | 76.8 | 76.8 | | 3 | 7.4 | 7.4 | | 4 | 15.4 | 15.4 | | 5 | 7.2 | 7.2 | | 6 | -51.4 | 0 | +------+-------+------+ 

Le résultat est correct. Bien que les cinq premiers enregistrements ne semblent pas satisfaire à la comparaison (les valeurs de a et b ne semblent pas être différentes), ils peuvent le faire parce que la différence entre les nombres apparaît autour de la dixième décimale, en fonction des facteurs tels que l’architecture informatique ou la version du compilateur ou le niveau d’optimisation. Par exemple, différents processeurs peuvent évaluer les nombres à virgule flottante différemment.

Si les colonnes d1 et d2 avaient été définies en tant que DECIMAL plutôt que DOUBLE, le résultat de la requête SELECT n’aurait contenu qu’une seule ligne, la dernière indiquée ci-dessus.

La méthode correcte pour effectuer une comparaison de nombres à virgule flottante consiste à déterminer d’abord une tolérance acceptable pour les différences entre les nombres, puis à effectuer la comparaison avec la valeur de tolérance. Par exemple, si nous convenons que les nombres à virgule flottante doivent être considérés comme identiques avec une précision de un sur dix mille (0,0001), la comparaison doit être écrite pour trouver des différences supérieures à la valeur de tolérance:

 mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 -> GROUP BY i HAVING ABS(a - b) > 0.0001; +------+-------+------+ | i | a | b | +------+-------+------+ | 6 | -51.4 | 0 | +------+-------+------+ 1 row in set (0.00 sec) 

À l’inverse, pour obtenir des lignes dont les nombres sont identiques, le test doit trouver des différences dans la valeur de tolérance:

 mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 -> GROUP BY i HAVING ABS(a - b) <= 0.0001; +------+------+------+ | i | a | b | +------+------+------+ | 1 | 21.4 | 21.4 | | 2 | 76.8 | 76.8 | | 3 | 7.4 | 7.4 | | 4 | 15.4 | 15.4 | | 5 | 7.2 | 7.2 | +------+------+------+ 5 rows in set (0.03 sec) 

Les valeurs à virgule flottante sont soumises à des dépendances de plate-forme ou d'implémentation. Supposons que vous exécutiez les instructions suivantes:

 CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0)); INSERT INTO t1 VALUES('1e+52','-1e+52'); SELECT * FROM t1; 

Sur certaines plateformes, l'instruction SELECT renvoie inf et -inf. Sur d'autres, il renvoie 0 et -0.

Une implication des problèmes précédents est que si vous essayez de créer un esclave de réplication en vidant le contenu de la table avec mysqldump sur le maître et en rechargeant le fichier de vidage dans l'esclave, les tables contenant des colonnes à virgule flottante peuvent différer entre les deux hôtes.

https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html

Règle dure et rapide

Si tout ce que vous avez à faire est d’append, soustraire ou multiplier les nombres que vous stockez, DECIMAL est le meilleur.

Si vous avez besoin de diviser ou de faire une autre forme d’arithmétique ou d’algèbre sur les données, vous serez presque certainement plus heureux avec le flottant. Les bibliothèques à virgule flottante et les processeurs Intel, le processeur en virgule flottante lui-même, ont des TON d’opérations pour corriger, corriger, détecter et gérer le blizzard des exceptions qui se produisent lors de fonctions mathématiques classiques, notamment les fonctions transcendantes.

En ce qui concerne l’exactitude, j’ai écrit un système de calcul qui calculait le pourcentage de consortingbution de plus de 3 000 comptes pour 3 600 unités budgétaires par mois au nœud de consolidation de cette unité, puis sur cette masortingce de pourcentages (3 000 + x 12 x 3 600). J’ai multiplié les montants budgétisés par les nœuds organisationnels les plus élevés aux trois niveaux suivants des nœuds organisationnels, puis calculé toutes les valeurs (3 000 + 12) pour les 3 200 unités de détail correspondantes. Des millions et des millions et des millions de calculs à virgule flottante en double précision, l’un d’entre eux rejetant le cumul de toutes ces projections dans une consolidation ascendante au plus haut niveau de l’organisation.

L’erreur totale en virgule flottante après tous ces calculs était ZERO . C’était en 1986, et les bibliothèques à virgule flottante sont aujourd’hui bien meilleures qu’elles ne l’étaient à l’époque. Intel effectue tous ses calculs intermédiaires de doubles avec une précision de 80 bits, ce qui élimine pratiquement toute erreur d’arrondi. Quand quelqu’un vous dit “c’est une erreur en virgule flottante”, c’est presque une certitude. PAS vrai.

float (et double ) représente des fractions binarys

decimal représente les fractions décimales

 declare @float as float(10) declare @Decimal as decimal(10) declare @Inetger as int set @float =10.7 set @Decimal =10.7 set @Inetger=@Decimal print @Inetger 

in float lorsque la valeur est définie sur l’entier print 10 mais en décimal 11