Devo usare double o float?


89

Quali sono i vantaggi e gli svantaggi dell'utilizzo di uno invece dell'altro in C ++?


Qualcuno ha provato a creare un array di float e un array di double e vedere se effettivamente ci sono 4 byte tra i membri su float e 8 byte tra i membri su double? È possibile che un compilatore / computer a 64 bit possa ancora riservare 8 byte per membro per i float anche se non hanno bisogno di così tanto.
user3015682

Risposte:


104

Se vuoi conoscere la vera risposta, dovresti leggere Quello che ogni informatico dovrebbe sapere sull'aritmetica a virgola mobile .

In breve, sebbene doubleconsenta una maggiore precisione nella sua rappresentazione, per alcuni calcoli produrrebbe errori maggiori . La scelta "giusta" è: usa tutta la precisione che ti serve ma non di più e scegli l'algoritmo giusto .

Molti compilatori eseguono calcoli in virgola mobile estesi in modalità "non rigorosa" comunque (cioè usano un tipo di virgola mobile più ampio disponibile nell'hardware, ad esempio 80 bit e 128 bit mobili), anche questo dovrebbe essere preso in considerazione. In pratica, difficilmente puoi vedere alcuna differenza di velocità : sono comunque nativi dell'hardware.


10
Sì. Con le moderne CPU che eseguono il prefetch di blocchi di memoria sempre più grandi, unità di elaborazione numerica parallela e architetture pipeline, il problema della velocità non è davvero un problema. Se hai a che fare con enormi quantità di numeri, forse la differenza di dimensione tra un float di 4 byte e un double di 8 byte potrebbe fare la differenza nell'impronta di memoria.
lavinio

5
Ebbene SSE (o qualsiasi unità in virgola mobile vertor) sarà in grado di elaborare il doppio del numero di flop in singola precisione rispetto alla doppia precisione. Se stai facendo solo x87 (o qualsiasi scalare) in virgola mobile, probabilmente non avrà importanza.
Greg Rogers

1
@ Greg Rogers: i compilatori non sono così intelligenti in questo momento. A meno che tu non stia scrivendo un assembly grezzo, non ha grandi differenze. E sì, questo potrebbe cambiare con l'evoluzione del compilatore.
J-16 SDiZ

Note aggiuntive: se non hai assolutamente idea di come siano i dati (o semplicemente non hai la minima idea di tutti i calcoli matematici nei collegamenti), usalo semplicemente double: è più sicuro nella maggior parte dei casi.
J-16 SDiZ

2
Questo documento non è breve.
jokoon

44

A meno che tu non abbia una ragione specifica per fare diversamente, usa double.

Forse sorprendentemente, è double e non float che è il tipo a virgola mobile "normale" in C (e C ++). Le funzioni matematiche standard come sin e log accettano i doppi come argomenti e restituiscono i doppi. Un normale letterale a virgola mobile, come quando scrivi 3.14 nel tuo programma, ha il tipo double. Non galleggiare.

Sui tipici computer moderni, i doppi possono essere veloci quanto i float, o anche più veloci, quindi le prestazioni di solito non sono un fattore da considerare, anche per calcoli di grandi dimensioni. (E quelli dovrebbero essere calcoli di grandi dimensioni , o le prestazioni non dovrebbero nemmeno entrare nella tua mente. Il mio nuovo computer desktop i7 può eseguire sei miliardi di moltiplicazioni di doppi in un secondo.)


26

È impossibile rispondere a questa domanda poiché non esiste un contesto per la domanda. Ecco alcune cose che possono influenzare la scelta:

  1. Implementazione del compilatore di float, double e double long. Lo standard C ++ afferma:

    Esistono tre tipi di virgola mobile: float, double e long double. Il tipo double fornisce almeno la stessa precisione del float e il tipo long double fornisce almeno la stessa precisione del double.

    Quindi, tutti e tre possono avere la stessa dimensione in memoria.

  2. Presenza di una FPU. Non tutte le CPU hanno FPU e talvolta i tipi a virgola mobile vengono emulati e talvolta i tipi a virgola mobile non sono supportati.

  3. Architettura FPU. L'FPU dell'IA32 è a 80 bit internamente: i float a 32 bit e 64 bit vengono espansi a 80 bit al caricamento e ridotti in negozio. C'è anche SIMD che può eseguire quattro float a 32 bit o due float a 64 bit in parallelo. L'uso di SIMD non è definito nello standard, quindi richiederebbe un compilatore che esegue analisi più complesse per determinare se SIMD può essere utilizzato, o richiede l'uso di funzioni speciali (librerie o intrinseche). Il risultato del formato interno a 80 bit è che puoi ottenere risultati leggermente diversi a seconda della frequenza con cui i dati vengono salvati nella RAM (quindi, perdendo precisione). Per questo motivo, i compilatori non ottimizzano particolarmente bene il codice in virgola mobile.

  4. Banda di memoria. Se un double richiede più spazio di archiviazione di un float, ci vorrà più tempo per leggere i dati. Questa è la risposta ingenua. Su un moderno IA32, tutto dipende da dove provengono i dati. Se è nella cache L1, il carico è trascurabile a condizione che i dati provengano da una singola riga della cache. Se si estende su più di una riga della cache, si verifica un piccolo overhead. Se è di L2, ci vuole un po 'di più, se è nella RAM, è ancora più lungo e, infine, se è su disco è un tempo enorme. Quindi la scelta di float o double è meno importante del modo in cui vengono utilizzati i dati. Se si desidera eseguire un piccolo calcolo su molti dati sequenziali, è preferibile un tipo di dati piccolo. Fare molti calcoli su un piccolo set di dati consentirebbe di utilizzare tipi di dati più grandi con effetti significativi. Se tu' accedendo ai dati in modo molto casuale, la scelta della dimensione dei dati non è importante: i dati vengono caricati nelle pagine / righe della cache. Quindi, anche se vuoi solo un byte dalla RAM, potresti ottenere 32 byte trasferiti (questo dipende molto dall'architettura del sistema). Oltre a tutto ciò, la CPU / FPU potrebbe essere super scalare (ovvero pipeline). Quindi, anche se un carico può richiedere diversi cicli, la CPU / FPU potrebbe essere impegnata a fare qualcos'altro (un moltiplicatore per esempio) che nasconde il tempo di caricamento in una certa misura.

  5. Lo standard non impone alcun formato particolare per i valori in virgola mobile.

Se disponi di una specifica, questa ti guiderà alla scelta ottimale. Altrimenti, dipende dall'esperienza su cosa usare.


16

Double è più preciso ma è codificato su 8 byte. float è di soli 4 byte, quindi meno spazio e meno precisione.

Dovresti stare molto attento se hai double e float nella tua applicazione. Ho avuto un bug a causa di questo in passato. Una parte del codice utilizzava float mentre il resto del codice utilizzava double. Copiare double in float e poi float in double può causare un errore di precisione che può avere un grande impatto. Nel mio caso, era una fabbrica chimica ... si spera che non abbia avuto conseguenze drammatiche :)

Penso che sia a causa di questo tipo di bug che il razzo Ariane 6 è esploso qualche anno fa !!!

Pensa attentamente al tipo da utilizzare per una variabile


3
Nota che 4/8 byts per float / double non è nemmeno garantito, dipenderà dalla piattaforma. Potrebbe anche essere lo stesso tipo ...
sleske

2
Il codice Ariane 5 ha tentato di convertire una virgola mobile a 64 bit, il cui valore era maggiore di 32.767, in un intero con segno a 16 bit. Ciò ha generato un'eccezione di overflow che ha indotto il razzo ad avviare la sua sequenza di autodistruzione. Il codice in questione era codice che è stato riutilizzato da un vecchio razzo più piccolo.
cmwt

5

Personalmente vado per il doppio tutto il tempo finché non vedo alcuni colli di bottiglia. Quindi prendo in considerazione il passaggio al float o l'ottimizzazione di qualche altra parte


4

Questo dipende da come il compilatore implementa double. È legale che double e float siano dello stesso tipo (ed è su alcuni sistemi).

Detto questo, se sono davvero diversi, il problema principale è la precisione. Un doppio ha una precisione molto maggiore a causa della sua differenza di dimensioni. Se i numeri che stai usando normalmente superano il valore di un float, usa un double.

Diverse altre persone hanno menzionato problemi di performance. Sarebbe esattamente l'ultimo della mia lista di considerazioni. La correttezza dovrebbe essere la tua considerazione n. 1.



2

Penso che indipendentemente dalle differenze (che come tutti sottolineano, i galleggianti occupano meno spazio e sono in generale più veloci) ... qualcuno ha mai avuto problemi di prestazioni usando il doppio? Dico usa il doppio ... e se in seguito decidi "wow, questo è davvero lento" ... trova il tuo collo di bottiglia delle prestazioni (che probabilmente non è il fatto che hai usato il doppio). POI, se è ancora troppo lento per te, vedi dove puoi sacrificare un po 'di precisione e usa il galleggiante.



1

Dipende molto dalla CPU, i compromessi più ovvi sono tra precisione e memoria. Con GB di RAM, la memoria non è un grosso problema, quindi è generalmente meglio usare doubles.

Per quanto riguarda le prestazioni, dipende molto dalla CPU. floatdi solito otterranno prestazioni migliori di quelle doublesu una macchina a 32 bit. Su 64 bit, doublei messaggi a volte sono più veloci, poiché è (di solito) la dimensione nativa. Tuttavia, ciò che conta molto di più della tua scelta dei tipi di dati è se puoi o meno trarre vantaggio dalle istruzioni SIMD sul tuo processore.


0

double ha una precisione maggiore, mentre i float occupano meno memoria e sono più veloci. In generale dovresti usare float a meno che tu non abbia un caso in cui non è abbastanza preciso.


5
Sui tipici computer moderni, double è veloce quanto float.
Thomas Padron-McCarthy,
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.