Float vs Double Performance


91

Ho fatto alcuni test di temporizzazione e ho letto anche alcuni articoli come questo (ultimo commento), e sembra che nella build di rilascio, i valori float e double richiedano la stessa quantità di tempo di elaborazione.

Com'è possibile? Quando il float è meno preciso e più piccolo rispetto ai valori doppi, come può il CLR raddoppiare nello stesso tempo di elaborazione?


10
Non penso che sia un duplicato esatto in quanto questo sta chiedendo il motivo dietro di esso, mentre l'altro utente chiede se è effettivamente più veloce, ma non necessariamente perché,
Joan Venge

Presumibilmente un duplicato esatto di I doppi sono più veloci dei float in C #? (rivendicato nel 2009 da un altro utente).
Peter Mortensen

Risposte:


155

Almeno sui processori x86, floate doubleciascuno verrà convertito in un reale a 10 byte dall'FPU per l'elaborazione. L'FPU non dispone di unità di elaborazione separate per i diversi tipi di virgola mobile che supporta.

Il vecchio consiglio che floatè più veloce di quanto doubleapplicato 100 anni fa, quando la maggior parte delle CPU non disponeva di FPU incorporate (e poche persone avevano chip FPU separati), quindi la maggior parte della manipolazione in virgola mobile veniva eseguita nel software. Su queste macchine (che erano alimentate dal vapore generato dalle fosse di lava), era più veloce usare floats. Ora l'unico vero vantaggio di floats è che occupano meno spazio (il che conta solo se ne hai milioni).


9
Forse non 100 anni fa ... Alcune FPU supportano la gestione nativa a livelli float, double e 80 bit e verranno eseguite più velocemente a lunghezze inferiori. Alcuni eseguiranno effettivamente alcune cose più lentamente anche a lunghezze più brevi ... :-)
Brian Knoblauch

4
Possibile eccezione: penso che il tempo per le divisioni dipenda dal numero di bit (1 ciclo di clock / 2 bit). I tempi che ho fatto per float vs double division sembrano coincidere con questo.
Neil Coffey

21
Avvertenza per il codice SIMD - dal momento che puoi impacchettare 2x float che doppi in un registro SIMD (es. SSE), potenzialmente operare su float potrebbe essere più veloce. Ma poiché è C #, è probabile che non accadrà.
Calyth

13
@P Daddy: Direi che il vantaggio dello spazio è importante a ogni livello della gerarchia della cache. Quando la cache dei dati di primo livello è grande 16 KB e stai elaborando un array di 4000 numeri, il float potrebbe essere facilmente più veloce.
Peter G.

4
@artificialidiot Mai dire mai;). SIMD è supportato in .NET dalla 4.6
ghord

13

Avevo un piccolo progetto in cui ho usato CUDA e posso ricordare che anche lì il float era più veloce del doppio. Per una volta il traffico tra Host e Device è inferiore (Host è la CPU e la RAM "normale" e Device è la GPU e la RAM corrispondente lì). Ma anche se i dati risiedono sul dispositivo tutto il tempo, è più lento. Penso di aver letto da qualche parte che questo è cambiato di recente o dovrebbe cambiare con la prossima generazione, ma non ne sono sicuro.

Quindi sembra che la GPU semplicemente non possa gestire la doppia precisione in modo nativo in quei casi, il che spiegherebbe anche perché di solito viene utilizzato GLFloat piuttosto che GLDouble.

(Come ho detto è solo per quanto posso ricordare, mi sono imbattuto in questo durante la ricerca di float vs double su una CPU.)


6
Le GPU sono animali completamente diversi dalle FPU. Come altri hanno detto, il formato nativo di FPU è la doppia precisione a 80 bit. E questo è da molto tempo ormai. Le GPU tuttavia si avvicinano a questo campo dalla singola precisione. È noto che le loro prestazioni DP FP (virgola mobile a doppia precisione) sono spesso esattamente la metà delle prestazioni SP FP. Sembra che abbiano spesso unità in virgola mobile SP e devono riutilizzare l'unità per coprire la doppia precisione. Che produce esattamente due cicli rispetto a uno. Questa è un'enorme differenza di prestazioni , che mi ha sbalordito quando l'ho affrontata.
Csaba Toth

1
Alcuni calcoli scientifici richiedono DP FP ei principali produttori di GPU non hanno pubblicizzato la riduzione delle prestazioni attorno a questo. Ora loro (AMD, nVidia) sembrano migliorare in qualche modo su questo argomento DP vs SP. I numerosi core di Intel Xeon Phi contengono FPU di Pentium e si noti che Intel ha sottolineato le sue capacità di doppia precisione . È lì che forse è davvero in grado di competere con i mostri GPGPU.
Csaba Toth

12

Tuttavia, ci sono ancora alcuni casi in cui i float sono preferiti: con la codifica OpenGL, ad esempio, è molto più comune utilizzare il tipo di dati GLFloat (generalmente mappato direttamente su float a 16 bit) poiché è più efficiente sulla maggior parte delle GPU rispetto a GLDouble.


3
Forse a causa della maggiore velocità di trasmissione dei dati? Se hai una matrice di numeri (z-buffer ecc.), La dimensione dei dati diventa più importante ed evitare conversioni tra float e double accelera la gestione. La mia ipotesi.
Lucero

2
Indubbiamente produttività. Inoltre, dato il contesto specializzato, è improbabile che si possa ottenere qualcosa di visibile dall'uso dei doppi sui float, quindi perché sprecare la memoria, specialmente perché è più breve sulle GPU rispetto alle CPU
Cruachan

1
Throughput e anche il fatto che SP FP (single precision floating point) è più il formato nativo delle FPU interne della GPU che DP FP (double precision). Vedi il mio commento alla risposta di @ Mene. Le FPU della GPU e della CPU sono animali molto diversi, la FPU della CPU pensa in DP FP.
Csaba Toth


12

Dipende dal sistema a 32 o 64 bit . Se compili a 64 bit, double sarà più veloce. Compilato a 32 bit su 64 bit (macchina e sistema operativo) ha reso fluttuante circa il 30% più veloce:

    public static void doubleTest(int loop)
    {
        Console.Write("double: ");
        for (int i = 0; i < loop; i++)
        {
            double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = Math.Sin(a);
            b = Math.Asin(b);
            c = Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    public static void floatTest(int loop)
    {
        Console.Write("float: ");
        for (int i = 0; i < loop; i++)
        {
            float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = (float) Math.Sin(a);
            b = (float) Math.Asin(b);
            c = (float) Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        doubleTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        time = DateTime.Now;
        floatTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        Thread.Sleep(5000);
    }

2
Hai considerato quel 30% potrebbe essere dovuto ai lanci extra che usi ??
Rasmus Damgaard Nielsen

@RasmusDamgaardNielsen I cast sono parte del problema poiché Mathfunziona con il doppio. Ma hai letto male il mio post: i miei test mi hanno mostrato fluttuare meglio nelle prestazioni.
Bitterblue

2
I risultati pubblicati sopra sono fasulli. I miei test mostrano che su una vecchia macchina a 32 bit con .NET 4.0 in modalità di rilascio, le prestazioni floate doublesono praticamente identiche. Differenza inferiore allo 0,3% se calcolata in media su molte prove indipendenti, in cui ciascuna prova ha esercitato operazioni di moltiplicazione, divisione e addizione su variabili concatenate consecutivamente (per evitare che eventuali ottimizzazioni del compilatore intralciassero). Ho provato una seconda serie di test con Math.Sin()e Math.Sqrt()e ho anche ottenuto risultati identici.
Salsa speciale
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.