Enorme diferença.
Como o nome indica, a double
tem 2x a precisão de [1] . Em geral, a possui 15 dígitos decimais de precisão, enquanto que 7.float
double
float
Veja como o número de dígitos é calculado:
double
possui 52 bits de mantissa + 1 bit oculto: log (2 53 ) ÷ log (10) = 15,95 dígitos
float
possui 23 bits mantissa + 1 bit oculto: log (2 24 ) ÷ log (10) = 7,22 dígitos
Essa perda de precisão pode levar ao aumento de erros de truncamento quando cálculos repetidos são feitos, por exemplo,
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
enquanto
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
Além disso, o valor máximo de float é de cerca de 3e38
, mas o dobro é de aproximadamente 1.7e308
, portanto, o uso float
pode atingir "infinito" (ou seja, um número de ponto flutuante especial) muito mais facilmente do que double
para algo simples, como calcular o fatorial de 60.
Durante o teste, talvez alguns casos de teste contenham esses números enormes, o que pode causar falhas nos programas se você usar flutuadores.
É claro que, às vezes, nem double
é preciso o suficiente, portanto, temos long double
[1] (o exemplo acima fornece 9.000000000000000066 no Mac), mas todos os tipos de ponto flutuante sofrem erros de arredondamento , portanto, se a precisão é muito importante (por exemplo, dinheiro processamento) você deve usar int
ou uma classe de fração.
Além disso, não use +=
para somar muitos números de ponto flutuante, pois os erros se acumulam rapidamente. Se você estiver usando Python, use fsum
. Caso contrário, tente implementar o algoritmo de somação Kahan .
[1]: Os padrões C e C ++ não especificam a representação de float
, double
e long double
. É possível que todos os três sejam implementados como IEEE de precisão dupla. No entanto, para a maioria das arquiteturas (gcc, MSVC; x86, x64, ARM) float
é de fato um número de ponto flutuante de precisão única IEEE (binary32) e double
é um número de ponto flutuante de precisão dupla IEEE (binary64).
Aqui está o que dizem os padrões C99 (ISO-IEC 9899 6.2.5 §10) ou C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8):
O padrão C ++ adiciona:
Eu sugeriria dar uma olhada na excelente aritmética O que todo cientista da computação deve saber sobre ponto flutuante que cobre o padrão de ponto flutuante IEEE em profundidade. Você aprenderá sobre os detalhes da representação e perceberá que há uma troca entre magnitude e precisão. A precisão da representação de ponto flutuante aumenta à medida que a magnitude diminui; portanto, os números de ponto flutuante entre -1 e 1 são os que têm maior precisão.
fonte
Dada uma equação quadrática: x 2 - 4.0000000 x + 3.9999999 = 0, as raízes exatas para 10 dígitos significativos são, r 1 = 2.000316228 er 2 = 1.999683772.
Usando
float
edouble
, podemos escrever um programa de teste:A execução do programa me dá:
Observe que os números não são grandes, mas você ainda obtém efeitos de cancelamento usando
float
.(De fato, o exposto acima não é a melhor maneira de resolver equações quadráticas usando números de ponto flutuante de precisão única ou dupla, mas a resposta permanece inalterada, mesmo se alguém usar um método mais estável .)
fonte
fonte
O tamanho dos números envolvidos nos cálculos de ponto flutuante não é o mais relevante. É o cálculo que está sendo realizado que é relevante.
Em essência, se você estiver executando um cálculo e o resultado for um número irracional ou decimal recorrente, haverá erros de arredondamento quando esse número for compactado na estrutura de dados de tamanho finito que você está usando. Como o dobro é o dobro do tamanho da flutuação, o erro de arredondamento será muito menor.
Os testes podem usar especificamente números que causariam esse tipo de erro e, portanto, testaram se você havia usado o tipo apropriado no seu código.
fonte
O tipo float, com 32 bits de comprimento, tem uma precisão de 7 dígitos. Embora possa armazenar valores com um intervalo muito grande ou muito pequeno (+/- 3,4 * 10 ^ 38 ou * 10 ^ -38), ele possui apenas 7 dígitos significativos.
O tipo double, com 64 bits de comprimento, possui um intervalo maior (* 10 ^ + / - 308) e precisão de 15 dígitos.
O tipo long double é nominalmente de 80 bits, embora um determinado emparelhamento do compilador / SO possa armazená-lo como 12-16 bytes para fins de alinhamento. O duplo longo tem um expoente que é ridiculamente enorme e deve ter 19 dígitos de precisão. A Microsoft, em sua infinita sabedoria, limita o dobro do comprimento a 8 bytes, o mesmo que o dobro simples.
De um modo geral, basta usar o tipo double quando precisar de um valor / variável de ponto flutuante. Os valores literais de ponto flutuante usados nas expressões serão tratados como duplos por padrão, e a maioria das funções matemáticas que retornam valores de ponto flutuante retornam dobras. Você economizará muitas dores de cabeça e lançamentos de texto se usar apenas o dobro.
fonte
Acabei de encontrar um erro que me levou uma eternidade para descobrir e potencialmente pode lhe dar um bom exemplo de precisão de flutuação.
A saída é
Como você pode ver após 0,83, a precisão diminui significativamente.
No entanto, se eu configurar o
t
dobro, esse problema não acontecerá.Levei cinco horas para perceber esse pequeno erro, que arruinou meu programa.
fonte
double
não é uma boa solução aqui. Você costumaint
contar e fazer uma multiplicação interna para obter seu valor de ponto flutuante.Os flutuadores têm menos precisão do que duplicam. Embora você já saiba, leia O que devemos saber sobre aritmética de ponto flutuante para entender melhor.
fonte
Ao usar números de ponto flutuante, você não pode confiar que seus testes locais serão exatamente os mesmos que são feitos no lado do servidor. O ambiente e o compilador provavelmente são diferentes no sistema local e onde os testes finais são executados. Já vi esse problema várias vezes em algumas competições do TopCoder, especialmente se você tentar comparar dois números de ponto flutuante.
fonte
As operações de comparação internas diferem como quando você compara 2 números com ponto flutuante, a diferença no tipo de dados (ou seja, flutuante ou duplo) pode resultar em resultados diferentes.
fonte
Se alguém trabalha com processamento incorporado, eventualmente o hardware subjacente (por exemplo, FPGA ou algum modelo específico de processador / microcontrolador) terá flutuado implementado de maneira ideal no hardware, enquanto o dobro utilizará rotinas de software. Portanto, se a precisão de um float for suficiente para atender às necessidades, o programa será executado algumas vezes mais rápido com o float do que o dobro. Conforme observado em outras respostas, cuidado com os erros de acumulação.
fonte
Diferentemente de um
int
(número inteiro), afloat
possui um ponto decimal, e o mesmo pode adouble
. Mas a diferença entre os dois é que adouble
é duas vezes mais detalhado que afloat
, o que significa que ele pode ter o dobro da quantidade de números após o ponto decimal.fonte