Perché i float fanno ancora parte del linguaggio Java quando i doppi sono per lo più consigliati?

83

In ogni luogo che ho guardato, dice che double è superiore a float in quasi tutti i modi. float è stato reso obsoleto da double in Java, quindi perché è ancora usato?

Programma molto con Libgdx e ti costringono a usare float (deltaTime, ecc.), ma mi sembra che double sia più facile da gestire in termini di memoria e archiviazione.

Ho letto anche Quando fa utilizzi float e quando utilizzi il doppio , ma se float è davvero valido solo per i numeri con molte cifre dopo il punto decimale, allora perché non possiamo usare solo una delle molte variazioni di double ?

C'è qualche ragione per cui le persone insistono nell'usare i float anche se in realtà non ha più alcun vantaggio? È troppo lavoro per cambiare tutto?

    
posta Eames 26.04.2016 - 18:08
fonte

6 risposte

168

LibGDX è un framework utilizzato principalmente per lo sviluppo di giochi.

Nello sviluppo del gioco di solito devi fare un sacco di numeri in tempo reale e qualsiasi prestazione puoi ottenere problemi. Ecco perché gli sviluppatori di giochi di solito usano il float quando la precisione del float è abbastanza buona.

La dimensione dei registri FPU nella CPU non è l'unica cosa da considerare in questo caso. In effetti, la maggior parte del pesante numero di crunch nello sviluppo del gioco è fatto dalla GPU, e Le GPU di solito sono ottimizzate per i float, non i doppi .

E poi c'è anche:

  • larghezza di banda del bus di memoria (quanto velocemente è possibile spalare i dati tra RAM, CPU e GPU)
  • Cache della CPU (che rende il precedente meno necessario)
  • RAM
  • VRAM

che sono tutte risorse preziose di cui ottieni il doppio quando usi float a 32 bit invece di 64 bit.

    
risposta data 26.04.2016 - 19:41
fonte
57

I float utilizzano la metà della memoria dei doppi.

Possono avere meno precisione del doppio, ma molte applicazioni non richiedono precisione. Hanno una gamma più ampia rispetto a qualsiasi formato a punti fissi di dimensioni simili. Pertanto, riempiono una nicchia che richiede vaste gamme di numeri ma non ha bisogno di alta precisione e dove l'utilizzo della memoria è importante. Ad esempio, li ho usati per grandi sistemi di reti neurali, ad esempio.

Spostandosi all'esterno di Java, sono anche ampiamente utilizzati nella grafica 3D, poiché molte GPU li usano come formato principale - al di fuori dei costosi dispositivi NVIDIA Tesla / AMD FirePro, il punto di virgola mobile a precisione doppia è molto lento sulle GPU.

    
risposta data 26.04.2016 - 19:51
fonte
47

Compatibilità all'indietro

Questo è il motivo numero uno per mantenere il comportamento in una lingua / libreria già esistente ISA / etc.

Pensa a cosa succederebbe se prendessero float da Java. Libgdx (e migliaia di altre librerie e programmi) non funzionerebbe. Ci vorrà un sacco di sforzi per ottenere tutto aggiornato, molto probabilmente anni per molti progetti (basta guardare la transizione da Python 2 a Python 3 che rompe la compatibilità con le versioni precedenti). E non tutto sarà aggiornato, alcune cose verranno interrotte per sempre perché i manutentori le hanno abbandonate, forse prima di quanto avrebbero fatto perché ci sarebbero voluti più sforzi di quelli che vogliono aggiornare, o perché non è più possibile per realizzare ciò che il loro software avrebbe dovuto fare.

Prestazioni

I doppi a 64 bit occupano il doppio della memoria e sono quasi sempre più lenti da elaborare rispetto ai float a 32 bit (le rare eccezioni sono quando si prevede che la capacità float a 32 bit venga utilizzata così raramente o per nulla, che non sia stato fatto alcuno sforzo per Ottimizza per loro. A meno che tu non stia sviluppando per hardware specializzato, non lo sperimenterai nel prossimo futuro.)

Particolarmente rilevante per te, Libgdx è una libreria di giochi. I giochi tendono ad essere più sensibili alle prestazioni rispetto alla maggior parte dei software. E le schede grafiche di gioco (ad esempio AMD Radeon e NVIDIA Geforce, non FirePro o Quadro) tendono ad avere prestazioni in virgola mobile a 64 bit molto deboli. Per gentile concessione di Anandtech, ecco come le prestazioni a doppia precisione si confrontano con le prestazioni a precisione singola su alcuni Le migliori schede di gioco disponibili di AMD e NVIDIA (a partire dall'inizio del 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

Si noti che le serie R9 Fury e GTX 900 sono più recenti rispetto alle serie R9 200 e GTX 700, pertanto le prestazioni relative per il punto mobile a 64 bit sono in diminuzione. Torna indietro abbastanza lontano e troverai la GTX 580, che aveva un rapporto 1/8 come la serie R9 200.

1/32 della performance è una penalità piuttosto grande da pagare se hai un vincolo di tempo limitato e non guadagni molto usando il doppio più grande.

    
risposta data 26.04.2016 - 22:43
fonte
35

Operazioni atomiche

Oltre a ciò che altri hanno già detto, uno svantaggio specifico di Java di double (e long ) è che le assegnazioni ai tipi primitivi a 64 bit non sono garantite per essere en.wikipedia.org/wiki/Linearizability#Primitive_atomic_instructions">atomic. Dalla Specifica della lingua Java, Java SE 8 Edition , pagina 660 (corsivo aggiunto):

17.7 Non-atomic Treatment of double and long

For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.

Yuck.

Per evitare ciò, devi dichiarare la variabile 64-bit con volatile parola chiave o utilizzare qualche altra forma di sincronizzazione attorno ai compiti.

    
risposta data 27.04.2016 - 07:53
fonte
3

Sembra che altre risposte abbiano perso un punto importante: le architetture SIMD possono elaborare meno / più dati a seconda se operano su double o float structs (ad esempio, otto valori float alla volta o quattro valori double alla volta).

Riepilogo delle considerazioni sulle prestazioni

  • float potrebbe essere più veloce su determinate CPU (ad esempio, alcuni dispositivi mobili).
  • float utilizza meno memoria, quindi in enormi serie di dati può ridurre sostanzialmente la memoria totale richiesta (disco rigido / RAM) e la larghezza di banda consumata.
  • float può far sì che una CPU consumi meno energia (non riesco a trovare un riferimento, ma se non è possibile almeno sembra plausibile) per calcoli a precisione singola rispetto ai calcoli a doppia precisione.
  • float consuma meno larghezza di banda e, in alcune applicazioni, è importante.
  • Le architetture SIMD possono elaborare fino a due volte la stessa quantità di dati, in genere.
  • float utilizza almeno la metà della memoria cache rispetto al doppio.

Riepilogo delle considerazioni sull'accuratezza

  • In molte applicazioni float è sufficiente
  • double ha molta più precisione comunque

Considerazioni di compatibilità

  • Se i tuoi dati devono essere inviati a una GPU (ad esempio, per un videogioco che utilizza OpenGL o qualsiasi altra rendering API), il formato in virgola mobile è considerevolmente più veloce di double (questo perché i produttori di GPU cercano di aumentare il numero di core grafici, e quindi cercano di salvare il maggior numero di circuiti possibile in ogni core, quindi ottimizzandoli per float permette di creare GPU con più core all'interno)
  • Le vecchie GPU e alcuni dispositivi mobili non possono accettare double come formato interno (per le operazioni di rendering 3D)

Suggerimenti generali

  • Sui moderni processori desktop (e probabilmente su una buona quantità di processori mobili) si può presumere che l'uso di variabili temporanee double sullo stack offra una precisione extra gratuitamente (precisione extra senza penalizzazione delle prestazioni).
  • Non usare mai più precisione del necessario (potresti non sapere quanta precisione hai realmente bisogno).
  • A volte sei semplicemente forzato dall'intervallo di valori (alcuni valori sarebbero infiniti se utilizzi float , ma potrebbero essere valori limitati se stai utilizzando double )
  • Usare solo float o solo double aiuta notevolmente il compilatore a SIMD-ify le istruzioni.

Vedi i commenti di PeterCordes per ulteriori approfondimenti.

    
risposta data 27.04.2016 - 19:16
fonte
0

Oltre agli altri motivi menzionati:

Se disponi di dati di misura, che si tratti di pressioni, flussi, correnti, tensioni o qualsiasi altra cosa, questo viene spesso eseguito con hardware dotato di ADC.

Normalmente un ADC ha 10 o 12 bit, 14 o 16 bit sono più rari. Ma restiamo fedeli a quelli a 16 bit: se misuriamo intorno al fondo scala, hai una precisione di 1/65535. Ciò significa che un passaggio da 65534/65535 a 65535/65535 è solo questo passo - 1/65535. Questo è all'incirca 1.5E-05. La precisione di un float è intorno a 1E-07, quindi molto meglio. Ciò significa che non perdi nulla utilizzando float per la memorizzazione di questi dati.

Se esegui calcoli eccessivi con float, ti rendi leggermente peggio che con doubles in termini di accuratezza, ma spesso non hai bisogno di tale precisione, dato che spesso non ti interessa hai appena misurato una tensione di 2 V o di 2.00002 V. Allo stesso modo, se converti questa tensione in una pressione, non ti importa se hai 3 bar o 3,00003 bar.

    
risposta data 29.04.2016 - 19:07
fonte

Leggi altre domande sui tag