mysql values Diferença entre o tipo de dados float e decimal



mysql unsigned float (10)

Não apenas específico para o MySQL, a diferença entre os tipos float e decimal é a maneira que eles representam valores fracionários. Tipos de ponto flutuante representam frações em binário, que só podem representar valores como {m*2^n | m, n Integers} {m*2^n | m, n Integers} . valores como 1/5 não podem ser representados com precisão (sem erro de arredondamento). Números decimais são similarmente limitados, mas representam números como {m*10^n | m, n Integers} {m*10^n | m, n Integers} . Decimais ainda não podem representar números como 1/3, mas é frequentemente o caso em muitos campos comuns, como finanças, que a expectativa é que certas frações decimais sempre possam ser expressas sem perda de fidelidade. Como um número decimal pode representar um valor de $0.20 (um quinto de dólar), ele é preferido nessas situações.

Que diferença faz quando uso tipos de dados float e decimais no MySQL ?.

Quando devo usar qual?


This é o que eu encontrei quando tive essa dúvida.

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

O decimal fez exatamente o que deveria fazer nestes casos, truncou o resto, perdendo assim a parte de 1/3.

Então, para somar o decimal é melhor, mas para divisões o float é melhor, até certo ponto, é claro. Quero dizer, usar o DECIMAL não lhe dará uma "aritmética à prova de falhas" de nenhuma maneira.

Espero que isto ajude.


declare @float as float(10)
declare @Decimal as decimal(10)
declare @Inetger as int

set @float =10.7
set @Decimal =10.7
set @Inetger[email protected]Decimal

print @Inetger

em flutuar quando o valor definido para inteiro imprimir 10, mas no decimal 11


O MySQL mudou recentemente a maneira como armazenam o tipo DECIMAL . No passado, eles armazenavam os caracteres (ou nybbles) para cada dígito, compreendendo uma representação em ASCII (ou nybble) de um número - versus - um inteiro de complemento de dois, ou algum derivado dele.

O formato de armazenamento atual para DECIMAL é uma série de inteiros de 1, 2, 3 ou 4 bytes cujos bits são concatenados para criar um número de complemento de dois com um ponto decimal implícito, definido por você e armazenado no esquema DB quando você declara a coluna e especifique o tamanho DECIMAL e a posição do ponto decimal.

Por exemplo, se você pegar um int de 32 bits, poderá armazenar qualquer número de 0 a 4.294.967.295. Isso cobrirá apenas 999.999.999, então se você jogou 2 bits e usou (1 << 30 -1) você não desistiu de nada. Cobrir todos os números de 9 dígitos com apenas 4 bytes é mais eficiente do que cobrir 4 dígitos em 32 bits usando 4 caracteres ASCII ou 8 dígitos nybble. (um nybble é de 4 bits, permitindo valores 0-15, mais do que o necessário para 0-9, mas você não pode eliminar esse desperdício indo para 3 bits, porque isso cobre apenas valores 0-7)

O exemplo usado nos documentos on-line do MySQL usa DECIMAL (18,9) como exemplo. Este é 9 dígitos à frente e 9 dígitos atrás do ponto decimal implícito, que conforme explicado acima requer o seguinte armazenamento.

Como 18 caracteres de 8 bits: 144 bits

Como 18 nybbles de 4 bits: 72 bits

Como 2 inteiros de 32 bits: 64 bits

Atualmente, o DECIMAL suporta um máximo de 65 dígitos, como DECIMAL (M, D), em que o maior valor para M permitido é 65, e o maior valor de D permitido é 30.

Assim, para não exigir trechos de 9 dígitos por vez, inteiros menores que 32 bits são usados ​​para adicionar dígitos usando números inteiros de 1,2 e 3 bytes. Por algum motivo que desafia a lógica, foram utilizados sinais assinados em vez de não assinados e, ao fazer isso, 1 bit é descartado, resultando nos seguintes recursos de armazenamento. Para intes de 1,2 e 4 bytes o bit perdido não importa, mas para o int de 3 bytes é um desastre porque um dígito inteiro é perdido devido à perda daquele bit único.

Com um int de 7 bits: 0 - 99

Com um int de 15 bits: 0 - 9.999

Com um int de 23 bits: 0 - 999.999 (0 - 9.999.999 com um int de 24 bits)

Os inteiros de 1,2,3 e 4 bytes são concatenados juntos para formar um "pool de bits" que o DECIMAL usa para representar o número precisamente como um inteiro de complemento de dois. O ponto decimal NÃO é armazenado, está implícito.

Isso significa que nenhuma conversão ASCII para int é necessária para que o mecanismo de banco de dados converta o "número" em algo que a CPU reconheça como um número. Sem arredondamentos, sem erros de conversão, é um número real que a CPU pode manipular.

Cálculos neste inteiro grande arbitrariamente devem ser feitos em software, já que não há suporte de hardware para este tipo de número, mas essas bibliotecas são muito antigas e altamente otimizadas, tendo sido escritas há 50 anos para suportar dados de ponto flutuante de precisão arbitrária IBM 370 Fortran . Eles ainda são muito mais lentos que a álgebra inteira de tamanho fixo feita com hardware inteiro da CPU, ou cálculos de ponto flutuante feitos na FPU.

Em termos de eficiência de armazenamento, como o expoente de um flutuante é anexado a cada flutuador, especificando implicitamente onde o ponto decimal é, ele é massivamente redundante e, portanto, ineficiente para o trabalho do banco de dados. Em um DB você já sabe onde o ponto decimal deve ir na frente, e cada linha na tabela que tem um valor para uma coluna DECIMAL precisa apenas olhar para a especificação 1 & somente de onde esse ponto decimal deve ser colocado, armazenado no esquema como os argumentos para um DECIMAL (M, D) como a implicação dos valores M e D.

As muitas observações encontradas aqui sobre qual formato deve ser usado para vários tipos de aplicativos estão corretas, então não vou insistir nesse ponto. Aproveitei o tempo para escrever isso aqui, porque quem quer que esteja mantendo a documentação on-line vinculada do MySQL não entende nenhuma das situações acima e depois de tentativas cada vez mais frustrantes de explicá-la a eles, desisti. Uma boa indicação de quão mal eles entenderam o que estavam escrevendo é a apresentação muito confusa e quase indecifrável do assunto.

Como um pensamento final, se você precisa de computação de ponto flutuante de alta precisão, houve avanços tremendos em código de ponto flutuante nos últimos 20 anos, e suporte de hardware para flutuação de Precisão Quádrupla e 96 bits estão ao virar da esquina, mas existem boas bibliotecas de precisão arbitrária se a manipulação do valor armazenado for importante.


Tipos de Ponto Flutuante (Valor Aproximado) - FLOAT, DOUBLE

Os tipos FLOAT e DOUBLE representam valores aproximados de dados numéricos. O MySQL usa quatro bytes para valores de precisão simples e oito bytes para valores de precisão dupla.

Para FLOAT, o padrão SQL permite uma especificação opcional da precisão (mas não o intervalo do expoente) em bits após a palavra-chave FLOAT entre parênteses. O MySQL também suporta essa especificação de precisão opcional, mas o valor de precisão é usado apenas para determinar o tamanho do armazenamento. Uma precisão de 0 a 23 resulta em uma coluna FLOAT de precisão única de 4 bytes. Uma precisão de 24 a 53 resulta em uma coluna DOUBLE de dupla precisão de 8 bytes.

O MySQL permite uma sintaxe fora do padrão: FLOAT (M, D) ou REAL (M, D) ou DOUBLE PRECISION (M, D). Aqui, “(M, D)” significa que os valores podem ser armazenados com até M dígitos no total, dos quais D dígitos podem ser após o ponto decimal. Por exemplo, uma coluna definida como FLOAT (7,4) será semelhante a -999.9999 quando exibida. O MySQL executa arredondamentos ao armazenar valores, portanto, se você inserir 999.00009 em uma coluna FLOAT (7,4), o resultado aproximado é 999.0001.

Como os valores de ponto flutuante são aproximados e não são armazenados como valores exatos, as tentativas de tratá-los como comparações exatas podem causar problemas. Eles também estão sujeitos a dependências de plataforma ou implementação.

Para máxima portabilidade, o código que requer armazenamento de valores de dados numéricos aproximados deve usar FLOAT ou DOUBLE PRECISION sem especificação de precisão ou número de dígitos.

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

Problemas com valores de ponto flutuante

Os números de ponto flutuante às vezes causam confusão porque são aproximados e não são armazenados como valores exatos . Um valor de ponto flutuante, conforme escrito em uma instrução SQL, pode não ser o mesmo que o valor representado internamente. As tentativas de tratar valores de ponto flutuante como exatas nas comparações podem levar a problemas. Eles também estão sujeitos a dependências de plataforma ou implementação. Os tipos de dados FLOAT e DOUBLE estão sujeitos a esses problemas. Para colunas DECIMAL, o MySQL executa operações com uma precisão de 65 dígitos decimais, o que deve resolver os problemas de imprecisão mais comuns.

O exemplo a seguir usa DOUBLE para demonstrar como os cálculos feitos usando operações de ponto flutuante estão sujeitos a erros de ponto flutuante.

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 |
+------+-------+------+

O resultado está correto. Embora os primeiros cinco registros pareçam não satisfazer a comparação (os valores de a e b não parecem ser diferentes), eles podem fazê-lo porque a diferença entre os números aparece em torno do décimo decimal, dependendo dos fatores. como a arquitetura do computador ou a versão do compilador ou o nível de otimização. Por exemplo, CPUs diferentes podem avaliar números de ponto flutuante de maneira diferente.

Se as colunas d1 e d2 tivessem sido definidas como DECIMAL em vez de DOUBLE, o resultado da consulta SELECT teria contido apenas uma linha - a última mostrada acima.

A maneira correta de fazer a comparação de números de ponto flutuante é primeiro decidir sobre uma tolerância aceitável para diferenças entre os números e, em seguida, fazer a comparação com o valor de tolerância. Por exemplo, se concordarmos que os números de ponto flutuante devem ser considerados os mesmos se forem iguais com uma precisão de um em dez mil (0,0001), a comparação deve ser escrita para encontrar diferenças maiores que o valor de tolerância:

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)

Por outro lado, para obter linhas em que os números são iguais, o teste deve encontrar diferenças dentro do valor de tolerância:

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)

Os valores de ponto flutuante estão sujeitos a dependências de plataforma ou implementação. Suponha que você execute as seguintes declarações:

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

Em algumas plataformas, a instrução SELECT retorna inf e -inf. Em outros, retorna 0 e -0.

Uma implicação dos problemas anteriores é que, se você tentar criar um escravo de replicação despejando o conteúdo da tabela com mysqldump no mestre e recarregar o arquivo de despejo no escravo, as tabelas contendo colunas de ponto flutuante podem diferir entre os dois hosts.

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


float (e double ) representa frações binárias

decimal representa frações decimais


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)

decimal é para quantidades fixas, como dinheiro, onde você deseja um número específico de casas decimais. Floats são para armazenar ... números de precisão de ponto flutuante.



Se você está atrás do desempenho e não da precisão, você deve notar que os cálculos com floats são muito mais rápidos que os decimais.





mysql