Por que os carros alegóricos ainda fazem parte da linguagem Java quando os duplos são mais recomendados?


84

Em todos os lugares que eu olhei, diz que doubleé superior a floatquase todos os aspectos. floatficou obsoleto doubleem Java, então por que ainda é usado?

Eu programo muito com o Libgdx e eles o forçam a usar float(deltaTime, etc.), mas me parece que doubleé mais fácil trabalhar com isso em termos de armazenamento e memória.

Também li Quando você usa float e quando usa double , mas se floaté realmente bom apenas para números com muitos dígitos após o ponto decimal, por que não podemos simplesmente usar uma das muitas variações de double?

Existe alguma razão para as pessoas insistirem em usar carros alegóricos, mesmo que isso não tenha mais vantagens? É muito trabalho mudar tudo?



58
Como você inferiu que "float é realmente bom apenas para números com muitos dígitos após o ponto decimal" das respostas a essa pergunta ?! Dizem o oposto direto !
Ordous

20
@ James Observe como se lê "números", não "dígitos". Flutuadores são piores quando você precisa de precisão ou alcance, eles são melhores quando você precisa de muitos e muitos dados não tão precisos. É o que essas respostas dizem.
Ordous

29
Por que temos bytee shorte intquando há long?
user253751

15
Uma pergunta muito mais apropriada é "por que você removeria uma palavra-chave e um tipo de dados primitivo de um idioma com décadas de código que seria interrompido sem motivo"?
Sara

Respostas:


169

O LibGDX é um framework usado principalmente para o desenvolvimento de jogos.

No desenvolvimento de jogos, você geralmente precisa fazer um monte de trituração de números em tempo real e qualquer desempenho que possa obter. É por isso que os desenvolvedores de jogos geralmente usam float sempre que a precisão do float é boa o suficiente.

O tamanho dos registros da FPU na CPU não é a única coisa que você precisa considerar neste caso. De fato, a maior parte do processamento pesado de números no desenvolvimento de jogos é feita pela GPU, e as GPUs geralmente são otimizadas para carros alegóricos, não duplos .

E depois há também:

  • largura de banda do barramento de memória (com que rapidez você pode extrair dados entre RAM, CPU e GPU)
  • Cache da CPU (que torna o anterior menos necessário)
  • RAM
  • VRAM

que são todos os recursos preciosos, dos quais você obtém o dobro quando usa o flutuador de 32 bits em vez do dobro de 64 bits.


2
Obrigado! Isso realmente ajudou porque você foi em profundidade sobre o que o uso de memória mudou e por que
Eames

7
Além disso, para operações SIMD, os valores de 32 bits podem ter o dobro da taxa de transferência. Como a resposta da 8bittree aponta, as GPUs têm uma penalidade de desempenho ainda maior com precisão dupla.
Paul A. Clayton

5
Muitos pipelines gráficos suportam half-floats de 16 bits para aumentar o desempenho onde a precisão é suficiente.
Adi Shavit

22
@phresnel Todos são. Você tem que mudar de posição, atualizar dados e o que não é. E esta é a parte simples . Então você tem que renderizar (= ler, girar, escalar e traduzir) as texturas, distâncias, colocá-lo no formato de tela ... Há muito o que fazer.
Sebb

8
@phresnel como ex-vice-presidente de operações de uma empresa de desenvolvimento de jogos, garanto a quase todos os jogos que há uma tonelada de processamento de números. Observe que geralmente está contido em bibliotecas e 100% abstraído do engenheiro, espero que eles entendam e respeitem que toda essa crise está acontecendo. Raiz quadrada inversa mágica, alguém?
precisa saber é o seguinte

57

Os carros alegóricos usam metade da memória dobra.

Eles podem ter menos precisão do que o dobro, mas muitos aplicativos não exigem precisão. Eles têm um alcance maior do que qualquer formato de ponto fixo de tamanho semelhante. Portanto, eles preenchem um nicho que precisa de amplos intervalos de números, mas não precisa de alta precisão, e onde o uso da memória é importante. Eu os usei para grandes sistemas de redes neurais no passado, por exemplo.

Além de Java, eles também são amplamente utilizados em gráficos 3D, porque muitas GPUs os utilizam como formato principal - fora dos dispositivos NVIDIA Tesla / AMD FirePro muito caros, o ponto flutuante de precisão dupla é muito lento nas GPUs.


8
Por falar em redes neurais, a CUDA atualmente oferece suporte para variáveis ​​de ponto flutuante de meia precisão (16 bits), ainda menos precisas, mas com ainda menos espaço na memória, devido ao aumento do uso de aceleradores no trabalho de aprendizado de máquina.
JAB

E quando você programar FPGAs você tende a selecionar a quantidade de bits tanto para mantissa e expoente manualmente de cada vez: v
Sebi

48

Compatibilidade com versões anteriores

Esta é a razão número um para manter o comportamento em um idioma / biblioteca / ISA / etc já existente .

Considere o que aconteceria se eles retirassem carros alegóricos do Java. Libgdx (e milhares de outras bibliotecas e programas) não funcionariam. Será necessário muito esforço para atualizar tudo, possivelmente anos para muitos projetos (basta olhar para a transição de Python 2 para Python 3 de quebra de compatibilidade com versões anteriores). E nem tudo será atualizado, algumas coisas serão quebradas para sempre porque os mantenedores os abandonaram, talvez mais cedo do que teriam, porque seria necessário mais esforço do que eles desejam atualizar ou porque não é mais possível realizar o que seu software deveria façam.

atuação

As duplas de 64 bits ocupam o dobro da memória e são quase sempre mais lentas do que as flutuações de 32 bits (as exceções muito raras são quando a capacidade de flutuação de 32 bits deve ser usada tão raramente ou de maneira alguma, que nenhum esforço foi feito para otimizá-las A menos que você esteja desenvolvendo para hardware especializado, não poderá experimentar isso em um futuro próximo.)

Especialmente relevante para você, o Libgdx é uma biblioteca de jogos. Os jogos tendem a ser mais sensíveis ao desempenho do que a maioria dos softwares. E placas gráficas de jogos (ou seja, AMD Radeon e NVIDIA Geforce, não FirePro ou Quadro) tendem a ter um desempenho de ponto flutuante de 64 bits muito fraco. Cortesia de Anandtech, veja como o desempenho de precisão dupla se compara ao desempenho de precisão única em algumas das principais placas de jogos da AMD e da NVIDIA disponíveis (no início de 2016)

AMD
Card    R9 Fury X      R9 Fury       R9 290X    R9 290
FP64    1/16           1/16          1/8        1/8

NVIDIA
Card    GTX Titan X    GTX 980 Ti    GTX 980    GTX 780 Ti
FP64    1/32           1/32          1/32       1/24

Observe que as séries R9 Fury e GTX 900 são mais recentes que as séries R9 200 e GTX 700; portanto, o desempenho relativo do ponto flutuante de 64 bits está diminuindo. Volte o suficiente e você encontrará a GTX 580, que tinha uma proporção de 1/8 como a série R9 200.

1/32 do desempenho é uma penalidade muito grande a pagar se você tiver uma restrição de tempo apertada e não ganhar muito usando o dobro maior.


1
observe que o desempenho do ponto flutuante de 64 bits está diminuindo em relação ao desempenho de 32 bits devido a instruções de 32 bits cada vez mais altamente otimizadas, não porque o desempenho real de 64 bits está diminuindo. isso também depende da referência real usada; Pergunto-me se o déficit de desempenho de 32 bits em destaque na esses parâmetros é devido a problemas de largura de banda de memória, bem como real computacional velocidade
sig_seg_v

Se você vai falar sobre o desempenho de DP em placas gráficas, você definitivamente deve mencionar o Titan / Titan Black. Ambos possuem mods que permitem que o cartão atinja 1/3 de desempenho, ao custo de desempenho de precisão única.
SGR

@sig_seg_v Definitivamente, existem pelo menos alguns casos em que o desempenho de 64 bits diminui absolutamente, não apenas relativamente. Veja esses resultados para obter um benchmark Folding @ Home de precisão dupla, onde um GTX 780 Ti supera um GTX 1080 (outra placa de proporção 1/32) e uma 980 Ti e, no lado da AMD, o 7970 (uma placa de proporção 1/4) , assim como o R9 290 e o R9 290X, superam a série R9 Fury. Compare isso com a versão de precisão única do benchmark , onde todos os cartões mais novos superam facilmente seus antecessores.
8bittree

36

Operações atômicas

Além do que outros já disseram, uma desvantagem específica de Java de double(e long) é que não é garantido que as atribuições para tipos primitivos de 64 bits sejam atômicas . Na especificação da linguagem Java, Java SE 8 Edition , página 660 (ênfase adicionada):

17.7 Tratamento não atômico de doubleelong

Para os fins do modelo de memória da linguagem de programação Java, uma única gravação em um valor não volátil longou doubleé tratada como duas gravações separadas: uma para cada metade de 32 bits. Isso pode resultar em uma situação em que um encadeamento vê os primeiros 32 bits de um valor de 64 bits de uma gravação e os segundos 32 bits de outra gravação.

Que nojo.

Para evitar isso, você deve declarar a variável de 64 bits com avolatile palavra - chave ou usar outra forma de sincronização nas atribuições.


2
Você não precisa sincronizar o acesso simultâneo a entradas e flutuações de qualquer maneira para evitar atualizações perdidas e torná-las voláteis para evitar o cache excessivo? Estou errado ao pensar que a única coisa que a atomicidade int / float impede é que eles nunca possam conter valores "mistos" que não deveriam conter?
Traubenfuchs

3
@ Traubenfuchs Ou seja, de fato o que é garantido lá. O termo que ouvi usado para isso é "rasgar" e acho que captura bem o efeito. O modelo da linguagem de programação Java garante que os valores de 32 bits, quando lidos, terão um valor que foi gravado neles em algum momento. Essa é uma garantia surpreendentemente valiosa.
precisa

Este ponto sobre atomicidade é super importante. Uau, eu tinha esquecido esse fato importante. Contra-intuitivo, como tendemos a pensar nos primitivos como sendo atômicos por natureza. Mas não atômico neste caso.
Basil Bourque

3

Parece que outras respostas perderam um ponto importante: As arquiteturas do SIMD podem processar menos / mais dados, dependendo se operam doubleou se floatestruturam (por exemplo, oito valores flutuantes por vez ou quatro valores duplos por vez).

Resumo das Considerações de Desempenho

  • float pode ser mais rápido em determinadas CPUs (por exemplo, determinados dispositivos móveis).
  • float usa menos memória, portanto, em grandes conjuntos de dados, pode reduzir substancialmente a memória total necessária (disco rígido / RAM) e a largura de banda consumida.
  • float pode fazer com que uma CPU consuma menos energia (não consigo encontrar uma referência, mas se não for possível, pelo menos parece plausível) para cálculos de precisão única em comparação com cálculos de precisão dupla.
  • float consome menos largura de banda e, em alguns aplicativos, o que importa.
  • As arquiteturas SIMD podem processar até o dobro da mesma quantidade de dados, porque normalmente.
  • float usa até metade da memória cache em comparação com o dobro.

Resumo das Considerações de Precisão

  • Em muitas aplicações floaté suficiente
  • double tem muito mais precisão de qualquer maneira

Considerações de compatibilidade

  • Se seus dados tiverem que ser enviados a uma GPU (por exemplo, para um videogame usando OpenGL ou qualquer outra API de renderização), o formato de ponto flutuante será consideravelmente mais rápido do que double(isso ocorre porque os fabricantes de GPU tentam aumentar o número de núcleos gráficos e assim, eles tentam economizar o máximo de circuitos possível em cada núcleo, otimizando para floatcriar GPUs com mais núcleos)
  • GPUs antigas e alguns dispositivos móveis simplesmente não podem aceitar doublecomo formato interno (para operações de renderização em 3D)

Dicas gerais

  • Nos modernos processadores de desktop (e provavelmente uma boa quantidade de processadores móveis), você pode basicamente assumir que o uso de doublevariáveis temporárias na pilha fornece precisão extra de graça (precisão extra sem penalização de desempenho).
  • Nunca use mais precisão do que você precisa (talvez você não saiba quanta precisão você realmente precisa).
  • Às vezes, você é forçado apenas pelo intervalo de valores (alguns valores seriam infinitos se você estiver usando float, mas podem ser valores limitados se você estiver usando double)
  • Usar apenas floatou apenas doubleajuda bastante o compilador a SIMD-ify as instruções.

Veja os comentários abaixo de PeterCordes para mais informações.


1
doubletemporários só é gratuito no x86 com o x87 FPU, não no SSE2. Auto-vetorizar um loop com doubletemporários significa descompactar floatpara double, o que requer uma instrução extra, e você processa metade do número de elementos por vetor. Sem a vetorização automática, a conversão geralmente pode ocorrer em tempo real durante uma carga ou armazenamento, mas significa instruções extras quando você está misturando carros alegóricos e duplos nas expressões.
Peter Cordes

1
Nas modernas CPUs x86, div e sqrt são mais rápidos para flutuar do que dobrar, mas outras coisas são a mesma velocidade (sem contar o problema de largura do vetor SIMD ou a largura de banda da memória / espaço em cache, é claro).
Peter Cordes

@ PeterCordes, obrigado por expandir alguns pontos. Eu não estava ciente da div e sqrt disparidade
GameDeveloper

0

Além dos outros motivos mencionados:

Se você possui dados de medição, sejam pressões, fluxos, correntes, tensões ou qualquer outra coisa, isso geralmente é feito com hardware com um ADC.

Um ADC normalmente possui 10 ou 12 bits, enquanto os de 14 ou 16 bits são mais raros. Mas vamos ficar com o de 16 bits - se medir em escala completa, você terá uma precisão de 1/65535. Isso significa que uma alteração de 65534/65535 para 65535/65535 é apenas esta etapa - 1/65535. Isso é aproximadamente 1.5E-05. A precisão de um flutuador é de cerca de 1E-07, muito melhor. Isso significa que você não perde nada usando floatpara armazenar esses dados.

Se você fizer cálculos excessivos com flutuadores, terá um desempenho levemente pior do que doublesem termos de precisão, mas muitas vezes não precisará dessa precisão, pois muitas vezes não se importa se apenas mediu uma tensão de 2 V ou 2.00002 V. , se você converter essa tensão em pressão, não se importará se possui 3 bar ou 3,00003 bar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.