Diferença entre o tipo de dados float e decimal

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

Quando devo usar qual?

Foi o que 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 sumr 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.

Um “float” na maioria dos ambientes é um tipo de ponto flutuante binário. Ele pode armazenar com precisão os valores da base 2 (até um certo ponto), mas não pode armazenar com precisão muitos valores da base 10 (decimal). Flutuadores são mais apropriados para cálculos científicos. Eles não são apropriados para a matemática mais orientada para os negócios, e o uso inadequado de carros alegóricos o incomodará. Muitos valores decimais não podem ser exatamente representados na base-2. 0.1 não pode, por exemplo, e você vê resultados estranhos como 1.0 - 0.1 = 0.8999999 .

Decimais armazenam números de base 10. Decimal é um bom tipo para a maioria das contas de negócios (mas qualquer tipo de “dinheiro” embutido é mais apropriado para cálculos financeiros), onde o intervalo de valores excede o fornecido por tipos inteiros, e valores fracionários são necessários. Decimais, como o nome indica, são projetados para números de base 10 – eles podem armazenar com precisão valores decimais (novamente, até certo ponto).

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ê tomar um int de 32 bits, poderá armazenar qualquer número de 0 a 4.294.967.295. Isso só cobrirá de forma confiável 999.999.999, então se você jogou fora 2 bits e usou (1 << 30 -1) você 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 de e 9 dígitos atrás do ponto decimal implícito, que como 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 resources 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 desse 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 database 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 número inteiro arbitrariamente grande 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 database. 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 grandes avanços no código de ponto flutuante nos últimos 20 anos, e o suporte de hardware para flutuação de Precisão Quádrupla e 96 bits está ao virar da esquina, mas existem boas bibliotecas de precisão arbitrária se a manipulação do valor armazenado for importante.

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 podem representar apenas 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 muitas vezes é 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.

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

 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) 

Flutuador:

Um pequeno número de ponto flutuante (precisão simples). Os valores permitidos são -3.402823466E + 38 a -1.175494351E-38.0 e 1.175494351E-38 a 3.402823466E + 38. Estes são os limites teóricos, baseados no padrão IEEE. O alcance real pode ser um pouco menor dependendo do seu hardware ou sistema operacional.

DECIMAL:

Um número de ponto fixo “exato” compactado. M é o número total de dígitos (a precisão) e D é o número de dígitos após o ponto decimal (a escala). O ponto decimal e (para números negativos) o sinal “-” não são contados em M. Se D for 0, os valores não terão ponto decimal ou parte fracionária. O número máximo de dígitos (M) para DECIMAL é 65. O número máximo de decimais suportados (D) é 30. Se D for omitido, o padrão é 0. Se M for omitido, o padrão será 10.

Eu achei isso útil:

Geralmente, os valores Flutuantes são bons para cálculos científicos, mas não devem ser usados ​​para valores financeiros / monetários. Para Business Oriented Math, use sempre Decimal.

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

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.

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 syntax 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 dependencies 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

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 igual ao valor representado internamente. As tentativas de tratar valores de ponto flutuante como comparações exatas podem causar problemas. Eles também estão sujeitos a dependencies 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 mais comuns de imprecisão.

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 cinco primeiros 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 iguais 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 dependencies 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

Regra Difícil e Rápida

Se tudo que você precisa fazer é adicionar, subtrair ou multiplicar os números que você está armazenando, o DECIMAL é o melhor.

Se você precisar dividir ou fazer qualquer outra forma de aritmética ou álgebra nos dados, certamente ficará mais feliz com o float. Bibliotecas de ponto flutuante e processadores Intel, o próprio processador de ponto flutuante, possuem TONs de operações para corrigir, corrigir, detectar e lidar com a nevasca de exceções que ocorrem ao executar funções matemáticas típicas – especialmente funções transcendentais.

Quanto à precisão, uma vez eu escrevi um sistema de orçamento que calculava a contribuição% de cada uma das 3.000 contas +, para 3.600 unidades de orçamento, por mês no nó de consolidação daquela unidade, então com base nessa matriz de porcentagens (3.000 x 12 x 3.600) Multipliquei os valores orçados pelos mais altos nós organizacionais para os próximos 3 níveis dos nós organizacionais e, em seguida, calculei todos os valores (3.000 + 12) para todas as 3.200 unidades de detalhe a partir disso. Milhões e milhões e milhões de cálculos de ponto flutuante de precisão dupla, qualquer um dos quais eliminaria a acumulação de todas essas projeções em uma consolidação de baixo para cima até o nível mais alto da organização.

O erro total de ponto flutuante depois de todos esses cálculos foi ZERO . Isso foi em 1986, e as bibliotecas de ponto flutuante hoje são muito, muito melhores do que eram naquela época. A Intel faz todos os seus cálculos intermediários de duplas em precisão de 80 bits, o que elimina o erro de arredondamento. Quando alguém diz “é um erro de ponto flutuante”, é quase certo que NÃO é verdade.

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

decimal representa frações decimais

 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 

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