Devo usar double ou float?

90

Quais são as vantagens e desvantagens de usar um em vez do outro em C ++?

AraK
fonte
Alguém já tentou fazer um array de floats e um array de doubles e ver se de fato há 4 bytes entre membros em floats e 8 bytes entre membros em doubles? É possível que um compilador / computador de 64 bits ainda reserve 8 bytes por membro para floats, embora eles não precisem de tanto.
user3015682

Respostas:

104

Se quiser saber a resposta verdadeira, você deve ler O que todo cientista da computação deve saber sobre aritmética de ponto flutuante .

Em suma, embora doublepermita maior precisão em sua representação, para certos cálculos produziria erros maiores . A escolha "certa" é: use a precisão necessária, mas não mais, e escolha o algoritmo certo .

Muitos compiladores fazem matemática de ponto flutuante estendida no modo "não estrito" de qualquer maneira (ou seja, usam um tipo de ponto flutuante mais amplo disponível em hardware, por exemplo, flutuante de 80 e 128 bits), isso também deve ser levado em consideração. Na prática, você dificilmente pode ver qualquer diferença na velocidade - eles são nativos do hardware de qualquer maneira.

J-16 SDiZ
fonte
10
Sim. Com CPUs modernas pré-buscando porções cada vez maiores de memória, unidades de processamento numérico paralelo e arquiteturas em pipeline, o problema de velocidade não é realmente um problema. Se você estiver lidando com grandes quantidades de números, então talvez a diferença de tamanho entre um float de 4 bytes e um double de 8 bytes possa fazer uma diferença no consumo de memória.
lavinio 02 de
5
Bem, SSE (ou qualquer unidade de ponto flutuante vertor) será capaz de processar duas vezes o número de flops em precisão simples em comparação com precisão dupla. Se você estiver fazendo apenas x87 (ou qualquer ponto flutuante escalar), provavelmente não fará diferença.
Greg Rogers
1
@Greg Rogers: os compiladores não são tão espertos no momento. A menos que você esteja escrevendo um assembly raw, não há grandes diferenças. E sim, isso pode mudar conforme o compilador evolui.
J-16 SDiZ
Uma observação adicional: Se você não tem absolutamente nenhuma ideia de como os dados se parecem (ou simplesmente não tem nenhuma pista de matemática nos links), apenas use double- é mais seguro na maioria dos casos.
J-16 SDiZ
@jokoon, não há nada simples em ponto flutuante e em toda a área de problemas de precisão / estabilidade numérica.
vonbrand de
45

A menos que você tenha algum motivo específico para fazer o contrário, use double.

Talvez surpreendentemente, é duplo e não flutuante que é o tipo de ponto flutuante "normal" em C (e C ++). As funções matemáticas padrão, como sin e log, recebem duplicatas como argumentos e retornam duplas. Um literal de ponto flutuante normal, como quando você escreve 3.14 em seu programa, tem o tipo double. Não flutuar.

Em computadores modernos típicos, os duplos podem ser tão rápidos quanto os flutuadores, ou até mais rápidos; portanto, o desempenho geralmente não é um fator a ser considerado, mesmo para cálculos grandes. (E esses teriam que ser grandes cálculos, ou o desempenho nem deveria passar pela sua mente. Meu novo computador desktop i7 pode fazer seis bilhões de multiplicações de duplas em um segundo.)

Thomas Padron-McCarthy
fonte
26

Esta pergunta é impossível de responder, pois não há contexto para a pergunta. Aqui estão algumas coisas que podem afetar a escolha:

  1. Implementação do compilador de floats, doubles e long doubles. O padrão C ++ afirma:

    Existem três tipos de ponto flutuante: float, double e long double. O tipo double fornece pelo menos tanta precisão quanto float, e o tipo long double fornece pelo menos tanta precisão quanto double.

    Portanto, todos os três podem ter o mesmo tamanho na memória.

  2. Presença de FPU. Nem todas as CPUs têm FPUs e às vezes os tipos de ponto flutuante são emulados e às vezes os tipos de ponto flutuante simplesmente não são suportados.

  3. Arquitetura FPU. A FPU do IA32 é de 80 bits internamente - 32 bits e 64 bits são expandidos para 80 bits na carga e reduzidos na loja. Há também o SIMD que pode fazer quatro floats de 32 bits ou dois floats de 64 bits em paralelo. O uso de SIMD não está definido no padrão, portanto, seria necessário um compilador que faça análises mais complexas para determinar se o SIMD pode ser usado ou requer o uso de funções especiais (bibliotecas ou intrínsecas). O resultado do formato interno de 80 bits é que você pode obter resultados ligeiramente diferentes dependendo da frequência com que os dados são salvos na RAM (assim, perdendo a precisão). Por esse motivo, os compiladores não otimizam o código de ponto flutuante muito bem.

  4. Largura de banda de memória. Se um double exigir mais armazenamento do que um float, demorará mais para ler os dados. Essa é a resposta ingênua. Em um IA32 moderno, tudo depende da origem dos dados. Se estiver no cache L1, a carga será insignificante, desde que os dados venham de uma única linha de cache. Se abranger mais de uma linha de cache, haverá uma pequena sobrecarga. Se for do L2, demora um pouco mais, se estiver na RAM então fica mais longo e finalmente, se estiver no disco é um tempo enorme. Portanto, a escolha de float ou double é menos importante do que a forma como os dados são usados. Se você deseja fazer um pequeno cálculo em muitos dados sequenciais, um pequeno tipo de dados é preferível. Fazer muitos cálculos em um pequeno conjunto de dados permitiria que você use tipos de dados maiores com qualquer efeito significativo. Se vocês' Ao acessar os dados de forma muito aleatória, a escolha do tamanho dos dados não é importante - os dados são carregados nas páginas / linhas de cache. Portanto, mesmo se você quiser apenas um byte da RAM, poderá obter 32 bytes transferidos (isso depende muito da arquitetura do sistema). Além de tudo isso, a CPU / FPU poderia ser superescalar (também conhecida como pipeline). Portanto, mesmo que uma carga possa levar vários ciclos, a CPU / FPU pode estar ocupada fazendo outra coisa (uma multiplicação, por exemplo) que oculta o tempo de carregamento até certo ponto.

  5. O padrão não impõe nenhum formato específico para valores de ponto flutuante.

Se você tiver uma especificação, isso o guiará para a escolha ideal. Caso contrário, depende da experiência sobre o que usar.

Skizz
fonte
16

Double é mais preciso, mas é codificado em 8 bytes. float tem apenas 4 bytes, portanto, menos espaço e menos precisão.

Você deve ter muito cuidado se tiver double e float em sua aplicação. Eu tive um bug devido a isso no passado. Uma parte do código estava usando float enquanto o resto do código estava usando double. Copiar duplo para flutuar e, em seguida, flutuar para dobrar pode causar um erro de precisão que pode ter um grande impacto. No meu caso, era uma fábrica de produtos químicos ... espero que não tenha consequências dramáticas :)

Acho que é por causa desse tipo de bug que o foguete Ariane 6 explodiu alguns anos atrás !!!

Pense cuidadosamente sobre o tipo a ser usado para uma variável

luc
fonte
3
Note que 4/8 bytes para float / double nem é garantido, vai depender da plataforma. Pode até ser do mesmo tipo ...
sleske
2
O código do Ariane 5 tentou converter um ponto flutuante de 64 bits, cujo valor era maior que 32.767, em um inteiro assinado de 16 bits. Isso gerou uma exceção de estouro que fez com que o foguete iniciasse sua sequência de autodestruição. O código em questão era um código que foi reutilizado de um foguete menor e mais antigo.
cmwt
5

Eu pessoalmente procuro o dobro até ver alguns gargalos. Então eu considero mover para flutuar ou otimizar alguma outra parte

Eric
fonte
4

Isso depende de como o compilador implementa o double. É legal que double e float sejam do mesmo tipo (e é em alguns sistemas).

Dito isso, se eles são de fato diferentes, o principal problema é a precisão. Um duplo tem uma precisão muito maior devido à diferença de tamanho. Se os números que você está usando normalmente excederem o valor de um float, use um double.

Várias outras pessoas mencionaram problemas de desempenho. Isso seria exatamente o último da minha lista de considerações. A correção deve ser sua consideração número 1.

JaredPar
fonte
2

Acho que independentemente das diferenças (que como todos apontam, os flutuadores ocupam menos espaço e são em geral mais rápidos) ... alguém já teve problemas de desempenho usando o double? Eu digo usar o dobro ... e se mais tarde você decidir "uau, isso é muito lento" ... encontre seu gargalo de desempenho (que provavelmente não é o fato de você ter usado o dobro). ENTÃO, se ainda for muito lento para você, veja onde você pode sacrificar alguma precisão e usar float.

Tom
fonte
1

Depende muito da CPU e as compensações mais óbvias são entre precisão e memória. Com GBs de RAM, a memória não é um grande problema, então geralmente é melhor usar doubles.

Quanto ao desempenho, depende muito da CPU. floats geralmente obterá melhor desempenho do que doubles em uma máquina de 32 bits. Em 64 bits, doubles às vezes são mais rápidos, pois é (geralmente) o tamanho nativo. Ainda assim, o que importará muito mais do que sua escolha de tipos de dados é se você pode ou não tirar proveito das instruções SIMD em seu processador.

Zifre
fonte
0

double tem maior precisão, enquanto floats ocupam menos memória e são mais rápidos. Em geral, você deve usar float, a menos que haja um caso em que não seja preciso o suficiente.

Tal Pressman
fonte
5
Em computadores modernos típicos, double é tão rápido quanto float.
Thomas Padron-McCarthy