Perché i float fanno ancora parte del linguaggio Java quando invece i doppi sono principalmente raccomandati?


84

In ogni luogo in cui ho guardato, dice che doubleè superiore a floatquasi in ogni modo. floatè stato reso obsoleto da doubleJava, quindi perché viene ancora utilizzato?

Programma molto con Libgdx e ti costringono a usare float(deltaTime, ecc.), Ma mi sembra che doublesia più semplice lavorare in termini di archiviazione e memoria.

Ho anche letto Quando usi il float e quando usi il doppio , ma se floatè davvero buono solo per numeri con molte cifre dopo il punto decimale, perché non possiamo semplicemente usare una delle tante varianti di double?

C'è qualche motivo per cui le persone insistono sull'uso dei float anche se in realtà non ha più vantaggi? È troppo lavoro per cambiarlo tutto?



58
In che modo hai dedotto "il float è davvero buono solo per i numeri con molte cifre dopo il punto decimale" dalle risposte a quella domanda ?! Dicono il contrario diretto !
Ordous,

20
@Eames Nota come dice "numeri", non "cifre". I galleggianti sono peggiori quando hai bisogno di precisione o portata, sono migliori quando hai bisogno di un sacco di dati non così precisi. Questo è quello che dicono quelle risposte.
Ordous,

29
Perché abbiamo bytee shorte intquando c'è long?
user253751

15
Una domanda molto più adatta è "perché dovresti rimuovere una parola chiave e un tipo di dati primitivo da una lingua con decenni di codice che si romperebbe senza motivo"?
Sara,

Risposte:


169

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

Nello sviluppo del gioco di solito devi fare un sacco di scricchiolii di numeri in tempo reale e qualsiasi prestazione tu possa ottenere. Ecco perché gli sviluppatori di giochi usano solitamente float ogni volta che la precisione del float è abbastanza buona.

La dimensione dei registri FPU nella CPU non è l'unica cosa che devi considerare in questo caso. In effetti la maggior parte dello scricchiolio dei numeri nello sviluppo del gioco è fatto dalla GPU e le GPU sono generalmente ottimizzate per i float, non i doppi .

E poi c'è anche:

  • larghezza di banda del bus di memoria (quanto velocemente puoi 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 il float a 32 bit anziché il doppio a 64 bit.


2
Grazie! Questo è stato di grande aiuto perché hai approfondito le modifiche all'utilizzo della memoria e perché
Eames,

7
Inoltre, per le operazioni SIMD, i valori a 32 bit possono avere una velocità doppia. Come sottolinea la risposta di 8bittree , le GPU hanno una penalità delle prestazioni ancora maggiore con doppia precisione.
Paul A. Clayton,

5
Molte pipeline grafiche supportano persino i semiflottanti a 16 bit per aumentare le prestazioni laddove la precisione è sufficiente.
Adi Shavit,

22
@phresnel Tutti lo sono. Devi spostare posizioni, aggiornare i dati e cosa no. E questa è la parte semplice . Quindi devi renderizzare (= leggere, ruotare, ridimensionare e tradurre) le trame, le distanze, portarlo nel formato degli schermi ... C'è molto da fare.
Sebb,

8
@phresnel come ex Vicepresidente Operazioni di un'impresa di sviluppo di giochi, ti assicuro che quasi tutti i giochi hanno un sacco di scricchiolii di numeri. Nota che di solito è contenuto nelle biblioteche e estratto al 100% dall'ingegnere, spero che capiscano e rispettino tutto ciò che sta succedendo. Magia radice quadrata inversa, qualcuno?
corsiKa

57

I float utilizzano metà della memoria rispetto ai doppi.

Potrebbero avere meno precisione dei doppi, ma molte applicazioni non richiedono precisione. Hanno una gamma più ampia rispetto a qualsiasi formato a virgola fissa di dimensioni simili. Pertanto, riempiono una nicchia che richiede ampie gamme di numeri ma non ha bisogno di alta precisione e in cui è importante l'utilizzo della memoria. Li ho usati per grandi sistemi di reti neurali in passato, ad esempio.

Spostandosi al di fuori 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 mobile a precisione doppia è molto lento sulle GPU.


8
Parlando di reti neurali, CUDA attualmente supporta le variabili a virgola mobile di precisione a 16 bit, ancora meno precise ma con impronte di memoria ancora più basse, a causa del maggiore utilizzo di acceleratori per il lavoro di machine learning.
JAB

E quando programmate FPGA tendete a selezionare manualmente la quantità di bit sia per la mantissa che per l'esponente ogni volta: v
Sebi,

48

Compatibilità con le versioni precedenti

Questa è la ragione numero uno per mantenere il comportamento in una lingua / biblioteca / ISA / ecc. Già esistente .

Considera cosa accadrebbe se togliessero i galleggianti da Java. Libgdx (e migliaia di altre librerie e programmi) non funzionerebbe. Ci vorrà un grande sforzo per aggiornare tutto, probabilmente anni per molti progetti (basta guardare alla transizione da Python 2 a Python 3 che rompe la compatibilità con le versioni precedenti). E non tutto sarà aggiornato, alcune cose saranno rotte per sempre perché i manutentori le hanno abbandonate, forse prima di quanto avrebbero fatto perché ci vorrebbe più sforzo di quello che vogliono aggiornare, o perché non è più possibile realizzare ciò che il loro software avrebbe dovuto fare.

Prestazione

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 eccezioni molto rare sono quelle in cui si prevede che la funzionalità di float a 32 bit venga utilizzata così raramente o per niente, che non è stato fatto alcuno sforzo per ottimizzare per loro A meno che non ti stia sviluppando per hardware specializzato, non lo sperimenterai nel prossimo futuro.)

Particolarmente rilevante per te, Libgdx è una libreria di giochi. I giochi hanno la tendenza ad essere più sensibili alle prestazioni rispetto alla maggior parte dei software. E le schede grafiche di gioco (ovvero AMD Radeon e NVIDIA Geforce, non FirePro o Quadro) tendono ad avere prestazioni a 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 alcune delle migliori carte da gioco AMD e NVIDIA disponibili (all'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 delle serie R9 200 e GTX 700, quindi le prestazioni relative per il virgola mobile a 64 bit sono in calo. Torna abbastanza lontano e troverai la GTX 580, che aveva un rapporto 1/8 come la serie R9 200.

1/32 della prestazione è una penalità abbastanza grande da pagare se si ha un tempo limitato e non si guadagna molto usando il doppio più grande.


1
si noti che le prestazioni per il virgola mobile a 64 bit sono in calo rispetto alle prestazioni a 32 bit a causa di istruzioni a 32 bit sempre più altamente ottimizzate, non perché le prestazioni effettive a 64 bit stanno diminuendo. dipende anche dal benchmark effettivo utilizzato; Mi chiedo se il deficit di prestazioni a 32 bit evidenziato in questi parametri di riferimento sia dovuto a problemi di larghezza di banda della memoria e all'effettiva velocità di calcolo
sig_seg_v

Se hai intenzione di parlare delle prestazioni DP nelle schede grafiche, dovresti assolutamente menzionare Titan / Titan Black. Entrambe dispongono di mod che consentono alla scheda di raggiungere prestazioni 1/3, a costo di prestazioni a precisione singola.
SGR,

@sig_seg_v Ci sono sicuramente almeno alcuni casi in cui le prestazioni a 64 bit diminuiscono in modo assoluto, non solo relativamente. Guarda questi risultati per un benchmark Folding @ Home a doppia precisione, in cui una GTX 780 Ti batte sia una GTX 1080 (un'altra scheda rapporto 1/32) e una 980 Ti, e sul lato AMD, la 7970 (una scheda rapporto 1/4) , così come R9 290 e R9 290X battono tutti la serie R9 Fury. Confrontalo con la singola versione di precisione del benchmark , in cui le nuove schede superano tutte le prestazioni dei loro predecessori.
settembre

36

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 come atomiche . Da Java Language Specification, Java SE 8 Edition , pagina 660 (enfasi aggiunta):

17.7 Trattamento non atomico di doubleelong

Ai fini del modello di memoria del linguaggio di programmazione Java, una singola scrittura su un valore non volatile longo un doublevalore viene trattata come due scritture separate: una per ogni metà a 32 bit. Ciò può provocare una situazione in cui un thread vede i primi 32 bit di un valore a 64 bit da una scrittura e i secondi 32 bit da un'altra scrittura.

Che schifo.

Per evitare ciò, devi dichiarare la variabile a 64 bit con lavolatile parola chiave o utilizzare un'altra forma di sincronizzazione attorno alle assegnazioni.


2
Non è necessario sincronizzare comunque l'accesso simultaneo a ints e float per impedire gli aggiornamenti persi e renderli volatili per impedire la memorizzazione nella cache eccessiva? Sbaglio nel pensare che l'unica cosa che impedisce l'atomicità int / float è che non possono mai contenere valori "misti" che non avrebbero dovuto contenere?
Traubenfuchs,

3
@Traubenfuchs Cioè, ciò che è garantito lì. Il termine che ho sentito usato per "strappare" e penso che catturi l'effetto abbastanza bene. Il modello del linguaggio di programmazione Java garantisce che i valori a 32 bit, quando letti, avranno un valore che è stato loro scritto ad un certo punto. Questa è una garanzia sorprendentemente preziosa.
Cort Ammon,

Questo punto sull'atomicità è estremamente importante. Caspita, mi ero dimenticato di questo fatto importante. Controintuitivo in quanto possiamo pensare che i primitivi siano di natura atomica. Ma non atomico in questo caso.
Basil Bourque,

3

Sembra che ad altre risposte sia mancato un punto importante: le architetture SIMD possono elaborare meno / più dati a seconda che operino doubleo floatstrutturino (ad esempio, otto valori float alla volta o quattro valori doppi alla volta).

Riepilogo delle considerazioni sulle prestazioni

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

Riepilogo delle considerazioni sulla precisione

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

Considerazioni sulla compatibilità

  • Se i tuoi dati devono essere inviati a una GPU (ad esempio, per un videogioco che utilizza OpenGL o qualsiasi altra API di rendering), 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 quanti più circuiti possibile in ciascun core, quindi l'ottimizzazione floatconsente di creare GPU con più core all'interno)
  • Le vecchie GPU e alcuni dispositivi mobili non possono accettare doublecome formato interno (per operazioni di rendering 3D)

Suggerimenti generali

  • Sui moderni processori desktop (e probabilmente una buona quantità di processori mobili) puoi sostanzialmente supporre che l'uso di doublevariabili temporanee nello stack offra una precisione aggiuntiva gratuita (precisione extra senza penalità di prestazione).
  • Non usare mai più precisione del necessario (potresti non sapere quanta precisione hai davvero bisogno).
  • A volte sei semplicemente forzato dall'intervallo di valori (alcuni valori sarebbero infiniti se stai usando float, ma potrebbero essere valori limitati se stai usando double)
  • Usare solo floato solo doublenotevolmente aiuta il compilatore a SIMD-ify le istruzioni.

Vedi i commenti qui sotto da PeterCordes per ulteriori approfondimenti.


1
doubleprovvisori è gratuito solo su x86 con FPU x87, non con SSE2. La vettorializzazione automatica di un ciclo con i doubleprovvisori significa decomprimere floatin double, il che richiede un'istruzione aggiuntiva ed elaborare metà degli elementi per vettore. Senza auto-vettorializzazione, la conversione può di solito avvenire al volo durante un carico o un negozio, ma significa istruzioni extra quando si mescolano float e doppi nelle espressioni.
Peter Cordes,

1
Sulle moderne CPU x86, div e sqrt sono più veloci per il float rispetto al doppio, ma altre cose hanno la stessa velocità (senza contare il problema della larghezza del vettore SIMD, o ovviamente la larghezza di banda della memoria / footprint della cache).
Peter Cordes,

@PeterCordes grazie per aver espanso alcuni punti. Non ero a conoscenza della disparità div e sqrt
GameDeveloper,

0

A parte gli altri motivi citati:

Se si dispone di dati di misura, che si tratti di pressioni, flussi, correnti, tensioni o altro, ciò viene spesso eseguito con hardware dotato di ADC.

Un ADC in genere ha 10 o 12 bit, 14 o 16 bit sono più rari. Ma atteniamoci a quello a 16 bit: se si misura su fondo scala, si ha una precisione di 1/65535. Ciò significa che un passaggio da 65534/65535 a 65535/65535 è proprio questo passaggio - 1/65535. Sono circa 1,5 E-05. La precisione di un galleggiante è di circa 1E-07, quindi molto meglio. Ciò significa che non perdi nulla usando floatper archiviare questi dati.

Se esegui calcoli eccessivi con i galleggianti, esegui prestazioni leggermente peggiori rispetto a quelle doublesin termini di precisione, ma spesso non hai bisogno di tale precisione, poiché spesso non ti importa se hai appena misurato una tensione di 2 V o 2,00002 V. Allo stesso modo , se converti questa tensione in una pressione, non ti importa se hai 3 bar o 3.00003 bar.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.